N’importe quel développeur vous le dira, c’est quand même plus sympa / rapide / facile de lire un code source quand il est “bien écrit”.
Cela fait maintenant quelques années que je développe, et depuis tout ce temps j’ai établi inconsciemment des règles de codage très simple que j’essaie de respecter pour que le code source que je produit soit le plus lisible possible.
1 – Nom de Fichier
Pour les noms de fichier, 2 règles simples :
- Les fichiers de “Classe” (Java comme .Net d’ailleurs) commencent par une Majuscule. Ensuite chaque “mot” à l’interieur du nom commencera par un Majuscule. Exemple : [WicketApplication.java], [DefaultMarkupResourceStreamProvider.java].
- Les fichiers de ressources (html, css, image, properties, javascript, etc) commencent par une Minuscule. Ensuite chaque “mot” à l’interieur du nom commencera par un Majuscule. Exemple : [index.html] , [jQuery.js].
Bien évidemment, il existe des exceptions. Wicket notamment impose de nommer les fichiers html et properties à l’identique de la Classe. Exemple : [HomePage.html], [Contact-fr-FR.properties].
2 – Longueur de ligne
Honnetement, la longueur de ligne m’importe peu. En effet, quasiment tous les IDE (Eclipse & Visual Studio pour ceux que je pratique) permettent de reformatter le code.
En plus, j’ai la chance d’avoir, au travail comme à la maison, un écran ‘Wide’ ce qui me permet de voir entierement même les grandes lignes.
3 – Accolades & indentation…
… parce que ça va de pair!
Les conventions, largement répandues, proposent de mettre les accolades en fin de ligne. Personnellement, je ne trouve ça pas très lisible.
public List<Util> tabUtil(String grp, boolean adm, List<Integer> exc){ Util[] tabU = rep.getUtil(grp); ArrayList<Util> temp = new ArrayList<Util>(); for (int i=0; i < tabU.length; i++){ if (!exc.contains(tabU[i].Id)){ if (tabU[i].adm == adm)temp.add(tabU[i]); } } return temp; }
C’est pour cela que je place toujours mes accolades sur la ligne d’en dessous. Certes les mauvaises langues diront que ca prend plus de place et que ca augmente le nombre de ligne de code source, mais au final le compilateur s’en fiche.
public List<Util> tabUtil(String grp, boolean adm, List<Integer> exc) { Util[] tabU = rep.getUtil(grp); ArrayList<Util> temp = new ArrayList<Util>(); for (int i=0; i < tabU.length; i++) { if (!exc.contains(tabU[i].Id)) { if (tabU[i].adm == adm) { temp.add(tabU[i]); } } } return temp; }
L’indentation reste celle préconisée, mais permet de réussir à chopper l’accolade ouvrante d’un seul coup d’oeil, plutot que d’avoir à effectuer une recherche approfondie.
4 – Espacement de texte
Utilisez des espaces! C’est gratuit!
N’en mettez pas trop! C’est pourri!
(parce que quelques exemples sont plus parlants…)
public JQLightboxLink(String id, String href, String classAttr, String albumRel, String label, String key) { super(id, href, label); this.classAttr = classAttr; this.albumRel = albumRel; this.setOutputMarkupId(true); if (key == null){key = JQLightboxPlugin.DEFAULT_KEY;} if (JQCore.get().getPlugin(key) == null){new JQLightboxPlugin(key);} this.plugin = (JQLightboxPlugin) JQCore.get().getPlugin(key); JQCore.get().getPlugin(key).attachComponentForDocumentReady(this); }
Avec un espacement correct c’est bien plus lisible!
public JQLightboxLink(String id, String href, String classAttr, String albumRel, String label, String key) { super(id, href, label); this.classAttr = classAttr; this.albumRel = albumRel; this.setOutputMarkupId(true); if (key == null) { key = JQLightboxPlugin.DEFAULT_KEY; } if (JQCore.get().getPlugin(key) == null) { new JQLightboxPlugin(key); } this.plugin = (JQLightboxPlugin) JQCore.get().getPlugin(key); JQCore.get().getPlugin(key).attachComponentForDocumentReady(this); }
Mais pas trop non plus :
public JQLightboxLink(String id, String href, String classAttr, String albumRel, String label, String key) { super(id, href, label); this.classAttr = classAttr; this.albumRel = albumRel; this.setOutputMarkupId(true); if (key == null) { key = JQLightboxPlugin.DEFAULT_KEY; } if (JQCore.get().getPlugin(key) == null) { new JQLightboxPlugin(key); } this.plugin = (JQLightboxPlugin) JQCore.get().getPlugin(key); JQCore.get().getPlugin(key).attachComponentForDocumentReady(this); }
J’essai toujours que l’espacement aide un peu plus la lecture des paragraphes. Mais comme vous le voyez, trop d’espace nuit gravement à la compréhension de l’ensemble.
5 – Faites comme si vous écriviez une rédaction
Ici, je vais essayer d’expliquer ma pensée quand à la clarté du code en lui même et les commentaires. (merci Greg pour la discussion que l’on a eu à ce sujet)
Voila, je pars du principe suivant : Si vous écrivez bien votre code source, vous pourrez le relire facilement, sans avoir besoin de recourir (trop) aux commentaires.
L’exemple suivant est poussé à l’extrême, mais c’est pour que tout le monde comprenne. Prennez la méthode suivante:
public List<Util> tabUtil(String grp, boolean adm, List<Integer> exc) { Util[] tabU = rep.getUtil(grp); ArrayList<Util> temp = new ArrayList<Util>(); for (int i=0; i < tabU.length; i++) { if (!exc.contains(tabU[i].Id)) { if (tabU[i].adm == adm) { temp.add(tabU[i]); } } } return temp; }
Certes c’est clair (du point de vue de l’espacement, des accolades, etc…), mais c’est compliqué de comprendre d’un simple coup d’oeil, ce que cette méthode fait au final (notamment après plusieurs mois sans y toucher, pensez à la maintenance de votre code source). Il sera donc absoluement nécessaire de recourir aux commentaires pour préciser les choses.
Cependant il est possible de rendre l’algorithme compréhensible en utilisant des termes intelligibles :
public List<Utilisateur> getUtilisateurs(String nomGroupe, boolean isAdministrateur, List<Integer> exclure) { Utilisateur[] tableauUtilisateur = wsRepository.getAllUtilisateurs(nomGroupe); ArrayList<Utilisateur> listeUtilisateurs = new ArrayList<Utilisateur>(); for (int compteurUtilisateur = 0; compteurUtilisateur < tableauUtilisateur.length; compteurUtilisateur++) { if (!exclure.contains(tableauUtilisateur[compteurUtilisateur].Id) && tableauUtilisateur[compteurUtilisateur].isAdministrateur == isAdministrateur) { listeUtilisateurs.add(tableauUtilisateur[compteurUtilisateur]); } } return listeUtilisateurs; }
Ici, il suffit de lire le texte qui est écrit pour comprendre, les termes utilisés (nom de méthodes, de variables, etc…) étant évocateurs. C’est plus verbeux, mais aussi beaucoup plus parlant.
Avec une syntaxe comme celle ci, les commentaires prennent toute leur valeur, car ils permettent effectivement de préciser quelque chose qui le mérite (algo complexe, note pour plus tard, précision de spéc); ce qui nous emmène au point suivant…
6 – N’utilisez pas de commentaires inutiles
On est pas des débiles!
public boolean isEtudiantExiste(int id, List<Etudiant> listeEtudiants) { // On parcourt la liste des etudiants for (int compteurEtudiant = 0; compteurEtudiant < listeEtudiants.length; compteurEtudiant++) { // Recupère l'étudiant dans la liste Etudiant currentEtudiant = listeEtudiants[compteurEtudiant]; // Recupère l'id de l'etudiant int currentId = currentEtudiant.getId(); // On compare les 2 id if (currentId == id) { // il sont égaux, alors on retourne vrai return true; } } // On a pas trouvé l'étudiant dans la liste, alors on retourne faux return false; }
7 – Sortez de votre bloc if aussi vite que possible
Voici un exemple bien horrible :
public void findShape(int flags, int point, String attribute, String[] list) { if(!findShapePoints(flags, point, attribute)) { if(!doFindShapePoints(flags, point, attribute)) { if(!findInShape(flags, point, attribute)) { if(!findFromGuide(flags,point)) { if(list.length > 0 && flags == 1) { doSomething(); } } } } } }
Et ce que ca pourrait donner :
public void findShape(int flags, int point, String attribute, String[] list) { if(findShapePoints(flags, point, attribute)) { return; } if(doFindShapePoints(flags, point, attribute)) { return; } if(findInShape(flags, point, attribute)) { return; } if(findFromGuide(flags,point)) { return; } if (!(list.length > 0 && flags == 1)) { return; } doSomething(); }
Evidemment cette deuxième méthode n’est pas géniale, mais elle permet de démontrer à quel point c’est plus simple de s’y retrouver.
8 – N’utilisez pas les blocs if alors que vous auriez pu faire sans
Du style :
public boolean isStringEmpty(String str) { if(str.equals("")) { return true; } else { return false; } }
Retirez tout simplement le bloc if :
public boolean isStringEmpty(String str) { return str.equals(""); }
Réflechissez et vous verrez que c’est applicable très souvent!
9 – Ne pas laissez du code commenté/mort dans votre code source
Tout le monde aujourd’hui range son code source dans un gestionnaire de code source comme SVN (pas vous ?).
Donc perdez cette mauvaise habitude de commenter des bouts de code source pour ne pas les perdre.
// public int methodeSuperMagique() // { // unPeuDeMagie(); // beaucoupDeMagie(); // int nombreMagique = encorePlusDeMagie(); // return nombreMagique; // }
Si vous n’avez pas besoin, supprimez!
Votre SVN garde une trace de ce que vous faites, vous pourrez revenir à l’ancienne version au besoin.
10 – De la Javadoc…
Je vous avoue que c’est le point le plus difficile pour moi, même si je me force à le faire.
Essayer de renseigner la javadoc de vos classes, cela vous aidera à coder (votre IDE vous propose en général des tooltips avec la javadoc), et aidera les gens qui risquent d’utiliser vos classes.
Cependant, attention de ne pas tomber dans le “Hannnnn mais t’as pas écrit TOUTE la javadoc”. Encore une fois c’est avec du bon sens qu’il faut faire ça.
Conclusion
Allez j’arrête là avec mes histoires. Le maître mot est “lisibilité“. Aucune règle n’égale le bon sens. Alors trouvez vos propres règles. Mais, gardez aussi à l’ésprit que vous ne serez peut être pas seul à lire votre code…
Imprimer cet article


J’ai les même “manies”! Mis à part le fait que je ne mets pas mes accolades à la ligne, l’indentation me suffisant à déduire qu’une accolade a été ouverte. Encore quelques efforts à faire du coté des espaces, j’ai toujours tendance à coller les parenthèse et autres. Enfin bon, un bon codeparser bien paramétré et c’est dans la poche! ^^
“Hannnnn mais t’as pas écrit TOUTE la javadoc”…
Celle là elle est pour moi, mais j’assume !! :p
Quand on en a marre d’avoir 5000 warnings dans son eclipse, on commence a faire de la doc … ou pas !
Rho la mauvaise foi de l’exemple sur les accolades, le premier n’est pas du tout indenté! Même si de toutes façons sur ce point tu m’as convaincu il y a quelques mois, après des années d’accolades à la fin de la ligne.
Point rarement évoqué, je te rejoins aussi sur les if imbriqués, qui méritent souvent d’être découpés, quitte à perdre en pseudo-optimisation, pour ne pas se retrouver avec du code indenté à 120 espaces.
Histoire de confronter nos points de vue maintenant, je m’efforce toujours d’écrire une “ressource” http comme une page web ou une feuille de style avec des minuscules, parce que c’est comme ça que j’ai appris à le faire et que ça m’a toujours paru plus propre.
Et pour les commentaires… les exemples que tu donnes sont triviaux! Sans raillerie aucune tu es proche dans tes exemples de la vision “stagiaire” du développement, à savoir une vision purement technique et algorithmique là où il faut prendre un peu de recul et retrouver l’aspect fonctionnel. Dans le même ordre d’idée c’est parfois important de commenter un code qui semble inutile mais qui aura une utilité plus tard; non je ne commente pas pour dire que je parcours une liste dans ma méthode qui fait 5 lignes mais je commente parce que je stocke dans cette liste ce qui me servira 50 ou 100 lignes plus bas, et si je en fais pas ça, je ne m’y retrouve pas.
Sur le point de la Javadoc, je rejoins Bouben. De toutes façons tu crées une méthode hop tu la commentes immédiatement. Mais tu verras avec un peu de pratique et d’expérience dans le dev ça viendra
Pour finir je voudrais juste faire part au monde de mon sentiment que l’essentiel, c’est avant tout de s’adapter au contexte d’un travail en équipe ou sur un projet existant afin de garder le tout cohérent… Je déteste retrouver (par exemple dans *mon* code) des variables nommees_comme_ca là où elles sontToutesCommeCa, des message d’erreurs en français là où tout était en anglais, des messages de log qui ne reprennent pas la même syntaxe… oui c’est un cri du coeur.
J’ai l’impression que c’est un spéciale dédicace pour moi cet article…
@Bastoune : oui heureusement qu’ils sont là les IDE !
@Butcho :
@Greg : Evidemment que je suis de mauvaise fois, sinon j’aurai pas fait cet exemple comme ça.
Concernant les commentaires, et je suis content que tu précise ta pensée, effectivement j’ai mis ici des commentaires de noob. Mais j’ai pas dit non plus qu’il fallait pas en mettre du tout.
Effectivement des commentaires qui peuvent te permettre de comprendre un peu mieux, ou de préciser ta pensée au moment ou tu as écrit le code source permettent souvent de sauver des heures de lecture/debug.
Chose étonnante, je suis d’accord avec toi, sur le point du travail en équipe (même si c’est souvent moi qui ai du m’adapter…).
@Tom : Mais non, j’avais cet article en tête depuis bien longtemps! T’inquiètes!
Allez je mets mon grain de sel !!!
Bon je suis à 100 % d’accord avec tout ce que tu dis Nico et je le fais depuis belle lurette : indentation/accolades à ligne au contraire des conventions Sun, noms de variables parlants, espacements, blocs inutiles …
Je confirme que t’as un problème avec la Javadoc ^^ et comme déjà dit, fais la immédiatement, quand tu en as l’habitude tu le fais même sans y penser.
Mais j’aimerai ajouter/préciser quelques points
1°) Ca dépend souvent du contexte client etc. Mais un truc m’a choqué dans un de tes exemples … ce n’est pas bien grave mais je trouve que ça a son importance : la langue utilisée pour les variables. En effet dans un exemple tu marques ceci : tableauUtilisateur = wsRepository
Oui je sais on ne maitrise pas forcément la langue des WebService que l’on utilise et parfois le client impose le français…
Mais quand on peut choisir autant garder tout le temps la même langue.
2°) Un bonne pratique que j’utilise et qui je crois mérite d’être évoquée, c’est de ne pas trop multiplier les points de sortie. Plutôt que de faire plusieurs return value1, return value2 etc. il peut être intéressant de structurer son code de manière à déclarer une variable retour en début de méthode, puis en fin de méthode de faire un return retour; ainsi on sait ou l’on sort, et on ne cherche pas trop longtemps en debug ce qui est exécuté ou non…
Certes ce n’est pas toujours faisable … mais ça peut éviter des problèmes … “oops le code ne s’exécute pas il y a eu un return avant que j’avais po vu …”
3°) Enfin tu dis “6 – N’utilisez pas de commentaires inutiles
On est pas des débiles!” suivi d’un exemple assez parlant.
Personnellement tu trouveras régulièrement ce genre de choses dans mon code. Pourquoi ?
Simplement parce que j’ai l’habitude d’écrire un pseudo algo en commentaire avant d’implémenter, voir parfois bien avant … et quand je reviens je code entre les commentaires… pourquoi les enlever ? … tant qu’ils restent concis/précis (1 ligne maxi) et évitent de lire le code justement. Parfois on n’est pas relu par des pros du code mais juste par quelqu’un qui cherche a comprendre le fonctionnement du programme sans être expert Java, et sans perdre de temps.
C’est une affaire de bon sens après comme tu dis.
4°) Un autre dernier point qui me vient à l’esprit tu parles du nommage des classes/ressources mais pas des packages, constantes … Par exemple les packages je ne mets jamais de “s”, les constantes public static String CONSTANTE = “INVARIABLE”;
Bon il y en aurait sans doute beaucoup a rajouter, mais je ne vais pas y passer la nuit non plus (j’ai eu rédigé des normes de développements précisant ce genre de choses de plusieurs dizaines de pages par le passé).
Donc le mot de la fin … avant de commencer un projet il est bon de fixer les conventions de codage et faire en sorte que chaque développeur les lisent, les comprennent et les appliquent. Et a mon sens surtout pas que chacun y aille de SA façon de coder aussi bonne soit elle…
Et vive les “code templates” Eclipse bien configurés associés au plugins tel Checkstyle configuré de manière cohérente avec ces précédents et suivant les normes de codages établies en début de projet et zou tout le monde est mis au pas ou détecté rapidement.
Et non Nico ce n’est pas une bonne pratique de désactiver checkstyle ou de le modifier poursuivre tes propres conventions :p il vaut mieux se plier aux règles dès le début et rester cohérent avec l’ensemble des développeurs. Ah non t’as pas fait ça un jour ? Enfin bon c’était le cadet de nos soucis à l’époque, je te pardonne
Je te rejoins carrément FinalSpy sur l’algorithme écrit en commentaire et codé ensuite.
Et merci d’avoir parlé de la langue des variables, point que j’ai zappé mais qui me tient beaucoup à coeur. Je suis un fervent défenseur du tout anglais, pour deux raisons principales :
- Pouvoir décrire plus de choses facilement avec moins de mots
- Ne pas avoir d’ambiguïtés sur l’accord de participes passés et adjectifs : puisque on ne peut pas mettre d’accents dans le code, on se retrouve parfois avec des incertitude quant au rôle précis de la variable.
Juste pour faire mon chieur “public static String CONSTANTE = “INVARIABLE” ” n’est pas une constante en java. C’est le mot clef final qui fait une constante, static sert juste à dire que c’est un attribut de la classe pas de l’objet instancié.
Mince on a réveillé Miumius. Garde bien son commentaire Nico, c’est collector ça aura de la valeur plus tard.
lol … c’est pas faux ^^
PAs bien réveillé sur ce coup là le gars !
J’ajoute un petit complément : les constantes en majuscules avec des unserscores (_) pour séparer les mots.
Les variables booléennes doivent toujours commencer par “is”. Ex : isUserValid. De même, pour les getters associés à un boolean, on ne met pas getUserValid() mais isUserValid()
Les noms des méthodes ne sont jamais un nom mais plutôt un adjectif ou un verbe. Par exemple mailSender(), c’est un nom à la con pour une méthode. Cela ne décrit pas l’action souhaitée. Alors que sendMail(), c’est beaucoup plus parlant.
Bref, je m’arrête là, le reste se trouve dans le livre ‘Code complete’ chez Microsoft Press. Un pavé imbouffable mais vraiement génial.
Attention sur l’utilisation du isX … il arrive que certaines bibliothèques tierces fonctionnant sur l’introspection ne reconnaissent pas correctement ces accesseurs.
De mémoire … et pour l’anecdote … Struts y est quelque peu allergique (après ça dépend peut-être des versions…) et oui je sais Struts c’est la préhistoire (pour rester poli ^^ )
@FinalSpy : Saligot ! oui la javadoc toussaaaa.
Pour ce qui concerne la langue utilisée, effectivement c’est mieux quand c’est uniforme. Mais attention à ne pas faire comme nos chères larves de l’académie française qui tentent absoluement de tout franciser. Et même si ton client souhaite du code source en français, tu va quand même pas remplacer Spring par printemps!
Pour le point 3°, c’est ton habitude ok, mais c’est franchement pas quelquechose que je conseillerai. Personnellement si l’algo parle de lui même je vois pas pourquoi laisser la polution du commentaire qui t’as permis d’en venir à écrire cela. Là c’est vraiment une question de point de vue.
Par contre je vois pas où tu as vu que je désactivai checkstyle!!! C’est un outil indispensable pour vérifier la cohérence du code source avec les conventions. Et je l’utilise tout le temps. Après, étant adepte du refactorring permanent, si y’avait des règles déconnantes …
@Miumius : Bien joué!
@Alex: je rejoins FinalSpy, mieux vaut que la variable s’appelle userValid. (beurk ca me rappelle de mauvais souvenirs cette histoire de struts…)
J’adore l’exemple du printemps … et toi alors tu code en quoi ? Ah ben moi cet hiver je me mets au printemps mais je continue d’hiberner ^^
@Nico&Alex pour le “is” je ne dis pas de ne pas l’utiliser … mais faut se méfier c’est tout ce que je dis.
@Nico pour Checkstyle t’es un peu trop Agile
… ok tu le desactives pas … tu te demmerdes pour qu’il soit en cohérence avec tes règles. C’est bien parfois … ou pas …
parce que du coup c’est plus cohérent avec celles des autres.
Enfin pour l’algo ben ca dépend si c’est juste un truc super simple compréhensible par le premier venu ok j’adhère. Maintenant si tu bosses avec des calculs un peu complexe, des variables pas forcément parlantes car résultats de calculs intermédiaires etc… ben ton code est incompréhensible, et un peu d’algo ça aide à éclaircir le truc.
J’ai un exemple en tête sur des calculs de coordonnées sur une grille formée d’hexagones en fonction de coordonnée x/y classiques … bref il faut déterminer des pentes de droites, des décalages de position etc.
Il y a plein de modulo, arrondis, de largeur/2 ou autres hauteur/3 etc.
Quelqu’un qui ne s’est pas un peu plongé dans la problématique ne comprendra rien au code … avec une ligne pour dire ce que l’on calcul et pourquoi, ça devient plus clair.
Bref pour moi ca dépend de pas mal de choses jedis pas qu’il faut absolument laisser son pseudo algo … je dis que parfois ca aide, et que parfois tout ne peut pas être mis dans la javadoc.
Pour moi la javadoc indique surtout ce que fais la méthode mais pas comment elle le fait dans le détail non plus. Quand on l’utilise on s’en fout de savoir toutes les étapes internes… par contre en debug ou en évolution on est content de comprendre ce qu’a voulu faire le gus précédent et pourquoi.
Comme tu disais au final ça reste une question de bon sens, on est d’accord la dessus.
userValid = “Grégo”;
Je découvre l’article à l’instant ainsi que les commentaires.
Pour revenir sur le tout anglais, c’est une solution mais attention tout de même. Quand on travaille dans des domaines techniques pointus, nos chers utilisateurs ont un certain vocabulaire (français, anglais voir même franglais !), si on utilise des termes traduit assez différents pour qu’ils ne soient pas parlant, ça peut poser des problèmes. Il faut alors mettre en place une table de traduction documentée et c’est pas franchement pratique à tenir à jour ou même à consulter.
Sans compter que tant qu’à traduire, autant traduire juste et c’est pas donné à tout le monde (même à Harraps!). Un cas qui me vient à l’esprit car je bosse dessus : Mesure d’épaisseur limite se traduit en “Wall thickness measurement”, ce n’est pas littérale.