Vous êtes sur la page 1sur 22

Coder proprement

Contenu
Coder proprement ............................................................................................................................2
Ce qu’en pensent les « grands »...................................................................................................2
Bjarne Strousrtup (créateur du C++) ........................................................................................2
Grady Booch (OO, Design Applications, OMT) .........................................................................2
Dave Thomas (grand-père d’Eclipse, Ruby) ..............................................................................3
Des noms significatifs ...................................................................................................................3
Méthodes ou fonctions ................................................................................................................4
Ne pas avoir d’effets de bord .......................................................................................................5
Commentaires ..............................................................................................................................9
Bons commentaires ..................................................................................................................9
Mauvais commentaires ......................................................................................................... 11
Mise en forme (Formatting) ...................................................................................................... 12
But : ....................................................................................................................................... 12
Mise en forme verticale......................................................................................................... 12
Densité verticale .................................................................................................................... 14
Fonctions dépendantes ......................................................................................................... 14
Ordre vertical......................................................................................................................... 15
Apparence horizontale .......................................................................................................... 16
Indentation ............................................................................................................................ 17
Règles d’équipe ..................................................................................................................... 18
Objets et structures de données ............................................................................................... 20
Gestion des erreurs ................................................................................................................... 21
Limite des données (boundaries) .............................................................................................. 22
Tests unitaires ........................................................................................................................... 22
3 règles du TDD (test driven developpment): ....................................................................... 22

Cégep Limoilou, départ. d’informatique 1


Coder proprement
Apprendre à écrire du code clair est difficile. Cela demande plus que la connaissance de
principes et de bonnes pratiques. Vous devez l’adopter, le pratiquer par vous-mêmes et voir vos
propres échecs. Vous devez aussi observer d’autres pratiques, lire du code et constater ce qui
distingue le beau code du code laid, voir le prix à payer pour aller vite et produire du code
cochon (p. xxvi ang.).

L’art du code clair. La seule façon d’aller plus vite est de produire du code propre. Mais qu’est-ce
que du code propre. C’est ce que nous allons voir, (p. 6)

Ce qu’en pensent les « grands »


Bjarne Strousrtup (créateur du C++)
« I like my code to be elegant and efficient. The logic should
be straightforward to make it hard for bugs to hide, the
dependencies minimal to ease maintenance, error handling
complete according to an articulated strategy, and
performance close to optimal so as not to tempt people to
make the code messy with unprincipled optimizations. Clean
code does one thing well. »

Élégant selon le dictionnaire veut dire plaisant à lire. Bjarne


insiste sur l’efficacité du code. Le mauvais code ne peut
qu’aboutir vers du mauvais. Corriger du mauvais code rend
le code encore pire en final. Le mauvais code tente de faire
trop de choses tout devient confus.

Le code propre focus sur un élément, chaque procédure, chaque fonction, chaque module
présente une seule idée, une seule pensée, un seul état. Pas de distraction, pas de pollution
d’idées, pas d’abondance de détails.

Grady Booch (OO, Design Applications, OMT)


« Clean code is simple and direct. Clean code reads like well-
written prose. Clean code never obscures the designer's intent
but rather is full of crisp abstractions and straightforward lines
of control. »

Cégep Limoilou, départ. d’informatique 2


Dave Thomas (grand-père d’Eclipse, Ruby)
« Clean code can be read, and enhanced by a developer other
than its original author. It has unit and acceptance tests. It has
meaningful names. It provides one way rather than many
ways for doing one thing. It has minimal dependencies, which
are explicitly defined, and provides a clear and minimal API.
Code should be literate since depending on the language, not
all necessaiy information can be expressed clearly in code
alone. »

Vous êtes des auteurs (« author »). Vous avez une


responsabilité vis-à-vis vos lecteurs une responsabilité de
bonne communication (devoir de clarté, de précision). Quand
vous écrivez du code, rappelez-vous que vous êtes des
auteurs qui écrivent pour des lecteurs qui vont juger vos travaux.

Des noms significatifs


Les noms sont partout dans les logiciels : variable, méthodes, arguments, classes, packages,
répertoire du code source, les fichiers jar, les exécutables, etc. Vous nommez, nommez et
nommez. Parce que vous faites cela souvent, vous pouvez le faire mieux.

Utiliser des noms qui révèlent vos intentions

int d ; //le temps écoulé en jour

int tempsEcouleEnJour;
int nombreDeJoursDepuisCreation;
int nombreDeJoursDepuisModification;
int ageDuFichierEnJours;

Pouvez-vous comprendre l’objectif du code suivant ?

public List<int []> getThem(){


List<int[]> list1 = new ArrayList<int[]>();
for(int[]x : theList)
if(x[0] == 4)
list1.add(x);
return list1;
}

Le problème vient non pas de la simplicité du code mais de son implicite : le niveau à partir
duquel le contexte n’est plus explicite dans le code lui-même. Le code exige implicitement que
nous connaissions les réponses aux questions suivantes :

1. Quelles sortes de choses trouve-t-on dans theList ?


2. Quelle est la signification de l’indice zéro sur un élément de theList ?
3. Quelle est la signification de la valeur 4 ?
4. Comment dois-je utiliser la liste retournée ?

Cégep Limoilou, départ. d’informatique 3


public List<int []> getFlaggedCells(){
List<int[]> flaggedCells = new ArrayList<int[]>();
for(int[]cell : gameBoard)
if(cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return falggedCells;
}

On peut améliorer et aller plus loin et créer une classe pour les cellules au lieu d’utiliser un
vecteur de int.

public List<Cell> getFlaggedCells(){


List<Cell> flaggedCells = new ArrayList<Cell>();
for(Cell cell : gameBoard)
if(cell.isFlagged())
flaggedCells.add(cell);
return falggedCells;
}

Donc, des noms représentatifs qui illustrent bien ce que vous faites.

Méthodes ou fonctions
La première règle est : Elles doivent être courtes.

La seconde règle : Elles doivent être plus petites encore.

Ne pas dépasser 80 caractères de large et un maximum de 24 lignes.

Faire une seule chose, bien, et uniquement cette chose.

Bien utiliser les modificateurs d’accès « private » et « public ».

Lire le code du début vers la fin (top to bottom)

Switch, c’est difficile de le faire court. Ne pas mettre plus de 2 lignes par case. Utiliser des
méthodes. ATTENTION, souvent le switch est utilisé, là où le polymorphisme pourrait être
exploité.

Des noms évidemment descriptifs.

Les arguments des fonctions

Le nombre idéal est 0, ensuite 1, 2 et 3 mais le moins possible.

initialiserPage(int longueur, int largeur, int marge g…)


initialiserPage(ParametresPage param)

Les arguments boolean sont à proscrire. Mieux vaut utiliser 2 méthodes séparées.

Cégep Limoilou, départ. d’informatique 4


render(boolean isSuite)

renderForSuite()
renderForSingle()

Vous pourriez croire que la réduction du nombre d’arguments en créant des objets est une
forme de tromperie, mais ce n’est pas le cas. Lorsque des groupes de variables sont passés
ensemble, à l’instar de x et y dans l’exemple précédent, il est fort probable qu’ils fassent partie
d’un concept qui mérite son propre nom.

Circle makeCircle(double x, double y, double radius)


Circle makeCircle(Point center, double radius)

public String unTest(String format, Object n, Object n2){


return format + n.getClass()+ n2.getClass();
}

public String unTest2(String format, Object ... args){


return format + args[0].getClass()+ args[1].getClass();
}

void monad(Integer… args);


void dyad(String name, Integer… args);
void triad(String name, int count, Integer… args);

Ne pas avoir d’effets de bord


Votre méthode doit faire une chose, mais elle exécute aussi autre chose.

Par exemple une méthode qui vérifie un mot de passe, initialise aussi celui-ci à la fin.

Figure 1 - p. 49 (fr)

Cégep Limoilou, départ. d’informatique 5


Même chose lorsque l’on déclare des attributs, on ne les initialise pas.

Un argument est une entrée pour une méthode, et non une sortie.

public void appendFooter(StringBuffer report);

report.appendFooter();

Utiliser bien l’OO.

Préférer les exceptions au lieu de retourner des codes d’erreur.

Enlever les try catch et préféré throws dans les classes de base.

Figure 2 - p. 53 (fr)

Ne pas se répéter. (init, suiteInit, Terminer, suiteTerminer)

Être structuré. UN seul RETURN, pas de break, pas de continue et jamais de goto. En gardant les
méthodes petites, on a moins la tentation d’utiliser les return, break et continue.

Cégep Limoilou, départ. d’informatique 6


Cégep Limoilou, départ. d’informatique 7
Cégep Limoilou, départ. d’informatique 8
Commentaires
Expliquez-vous dans le code.

Les commentaires ne vont pas améliorer du mauvais code, si c’est confus, les commentaires
vont empirer la situation au lieu de l’améliorer.

Bons commentaires
Commentaires légaux (copyright, normes, lois, etc.)

Information

Intention ou explication

Cégep Limoilou, départ. d’informatique 9


Clarification

Avertissements sur les conséquences

TODO (à faire)

Mise en évidence

JavaDoc toujours

Cégep Limoilou, départ. d’informatique 10


Mauvais commentaires
Meubler (mémérage)

Redondance (commentaires plus long à lire que le code)

Commentaires imprécis

Commentaires inutiles (chaque variable, chaque fonction)

Journal de commentaires (tous les petits changements)

Commentaires bruyants //default constructor //getter pour couleur

Dans les { accolades }

Au lieu de s’épancher dans un commentaire inutile et tapageur, le programmeur aurait mieux


fait de reconnaître que sa frustration pouvait être soulagée en améliorant la structure de son
code. Il aurait dû consacrer son énergie sur l’extraction du dernier bloc try/ catch dans une
fonction séparée.

Cégep Limoilou, départ. d’informatique 11


Mise en forme (Formatting)
But :
 Apparence professionnelle
 Règles simples de mise en forme
 Cohérence
 Être clair
 Important

Mise en forme verticale


Quelle devrait être la longueur d’un fichier source ?

Distribution des tailles de fichiers dans une échelle logarithmique (la hauteur d’une boîte
correspond à l’écart-type).

Qu’est-ce que cela veut dire? Il apparaît qu’il est possible de construire des systèmes
performants avec des fichiers sources qui ont en moyenne 200 lignes et avec un maximum de
500 lignes. Les petits fichiers sont naturellement plus faciles à comprendre.

La métaphore du journal
Si vous pensez à un journal bien écrit, qu’est-ce qui le distingue?

 Lecture verticale;
 Au début vous rencontrer un titre qui vous informe sur le sujet de la nouvelle et vous
permet de décider si oui ou non vous allez vous y intéresser;
 Le premier paragraphe vous donne un résumé de l’ensemble de la nouvelle en vous
masquant tous les détails tout en vous peignant les concepts à grands traits;
 Si vous continuez votre lecture vers le bas, les détails s’ajoutent et vous fournissent les
noms, dates et autres menus détails;

On veut qu’un fichier source se rapproche d’un journal.

Cégep Limoilou, départ. d’informatique 12


 Le nom doit être simple mais explicatif. Le nom par lui-même doit être suffisant pour
savoir si on est ou non dans le bon module.
 La partie haute du fichier source doit fournir l’information de haut niveau comme les
concepts et les algorithmes.
 Les détails devraient augmenter au fur et à mesure que nous avançons vers le bas du
fichier, pour fournir les fonctions de bas niveau et les détails dans le bas du fichier
source.
 Un journal est composé de nombreux articles, la plupart sont très petits. Certains sont
un peu plus grands. Très peu contiennent autant de texte que ce qu’une page peut
contenir. Cela rend le journal utile, efficace. Si le journal est composé d’une seule
histoire longue contenant une panoplie désordonnée de faits, de dates et
de noms, nous ne le lirions tout simplement pas.

Observons le fichier suivant.

Remarquez les lignes blanches. Si nous retirons ces lignes vides, comme dans le listing
précédent, nous remettons considérablement en question la lisibilité du code.

Cégep Limoilou, départ. d’informatique 13


Densité verticale
Ici on veut exprimer les liens qui relient les concepts. Les lignes de code qui sont étroitement
liées doivent clairement ressortir. Remarquez la rupture de liens par la présence de
commentaires inutiles…

Beaucoup mieux, mais absence de commentaires, de JavaDoc :o(.

Fonctions dépendantes
Si une fonction en appelle une autre, elles doivent être verticalement proches et l’appelant doit
être le plus près au-dessus de l’appelée.

Cégep Limoilou, départ. d’informatique 14


Ordre vertical
Comme un journal, on espère les plus importants concepts au début et on espère qu’ils soient
exprimés avec le moins possibles d’éléments polluants. On s’attend à rencontrer les détails à la
fin du fichier. Cela permet de parcourir les fichiers sources en découvrant l’essentiel des
fonctions au tout début sans avoir à plonger dans les détails puisque les fonctions secondaires
apparaissent à la fin. Le fichier source précédent est exprimé ainsi.

Cégep Limoilou, départ. d’informatique 15


Apparence horizontale
On utilise les espaces pour mettre en évidence les éléments associés ou dissociés. Par exemple,
pour bien voir l’affectation.

Une autre façon d’utiliser les espaces est d’accentuer la précédence des opérateurs.

MAUVAIS : Par contre aligner les attributs ainsi est inutile, difficile à entretenir et n’amène pas
vraiment de clarté.

BON : Plus clair et plus simple à entretenir.

Cégep Limoilou, départ. d’informatique 16


Indentation
L’indentation est importante.

Cégep Limoilou, départ. d’informatique 17


Règles d’équipe
Une équipe doit déterminer ses règles de codage. Cela prend environ 10 minutes. On décide de :

 La place des accolades,


 De la longueur de l’indentation,
 Comment nommer les classes,
 Les variables et les méthodes.
 …

Ensuite, on bloque ces règles, on les documente même dans les sources et… on les respecte.
Même si ce ne sont pas nos préférences, on doit respecter les règles parce ce que c’est le choix
de l’équipe.

« Rappelez-vous, la qualité d’un logiciel est faite d’un ensemble de documents qui se LISENT bien.
Les documents doivent avoir un style simple, uniforme et cohérent. Le lecteur ne doit pas
découvrir un style, un format ou une nomenclature différente d’un fichier source à un autre pour
le même projet. La dernière chose que nous voulons faire est d'ajouter à la complexité
du code source par le fouillis d’écriture contenant différents styles individuels. »

Pour terminer, un exemple de l’application des règles d’oncle Bob

Cégep Limoilou, départ. d’informatique 18


Cégep Limoilou, départ. d’informatique 19
Objets et structures de données
Les objets exposent leurs comportements mais masquent leurs données.

Les « get » et les « set » ne sont pas toujours pertinents, cela dévoile de l’information sur l’objet,
parfois une méthode mieux nommée est appropriée. C’est facile d’ajouter de nouvelles sortes
d’objets sans modifier les comportements. Mais, c’est difficile d’ajouter de nouveaux
comportements à des objets déjà existants. Parfois, les structures de données vont offrir une
meilleure solution si on sait que de nouveaux comportements risquent de s’ajouter aux objets et
si on sait qu’il n’y aura pas de nouvelles sortes d’objets.

Cégep Limoilou, départ. d’informatique 20


Nous constatons à nouveau la nature complémentaire de ces deux définitions ; elles sont
virtuellement opposées ! Cela révèle la dichotomie fondamentale entre les objets et les
structures de données :

Un code procédural (un code qui utilise des structures de données) facilite l’ajout de nouvelles
fonctions sans modifier les structures de données existantes. Un code orienté objet facilite
l’ajout de nouvelles classes sans modifier les fonctions existantes.

L’inverse est également vrai :

Un code procédural complexifie l’ajout de nouvelles structures de données car toutes les
fonctions doivent être modifiées. Un code orienté objet complexifie l’ajout de nouvelles
fonctions car toutes les classes doivent être modifiées.

Par conséquent, ce qui est difficile pour l’orienté objet est facile pour le procédural, tandis que
ce qui est difficile pour le procédural est facile pour l’orienté objet !

Gestion des erreurs


Quelque chose peut mal fonctionner, les entrées peuvent être anormales ou un périphérique
peut être en erreur. Votre programme doit pouvoir indiquer quoi faire dans une situation
exceptionnelle, mais cela ne veut pas dire que le programme doit s’obscurcir.

 Utiliser les exceptions au lieu des codes d’erreur.

Cégep Limoilou, départ. d’informatique 21


 Écrire les clauses try…catch…finally en premier.
 Ne pas retourner de valeur nulle.
 Ne pas passer de valeur nulle.

Limite des données (boundaries)


On a rarement le plein contrôle de notre production, on utilise du logiciel libre, du code fabriqué
par un collègue, du code provenant d’une tierce librairie (third-party package). Il y a comme une
tension entre les producteurs de librairies et les utilisateurs.

Par exemple, si on regarde l’interface Map de l’Api de Java, on découvre que cette classe est
pleine de possibilités et probablement la plupart du temps trop large pour nos besoins.

http://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html

Utiliser les génériques améliore car cela limite le nombre de « cast ».

Mais cela ne résout pas le problème du fait que l’interface Map est trop large pour nos besoins.

Encapsuler la structure de donnée est une autre solution plus limitative.

L’interface est cachée, ses frontières également, la classe est capable d’évoluer, mais on peut
aussi contrôler la demande.

Tests unitaires
Devrait toujours être dans des classes séparées. Idéalement xUnit.

3 règles du TDD (test driven developpment):


1. Écrire les tests unitaires avant le code de production;
2. Vérifier que le test échoue (puisque le code source n’existe pas) avant de vérifier qu’il
est valide;
3. Vérifier que le code passe après avoir écrit le source puis « refactoriser ».

1 « assert » par test, 1 concept par test et garder les tests unitaires propres et utiles.

Cégep Limoilou, départ. d’informatique 22

Vous aimerez peut-être aussi