• Louis, responsable projets

Appeler un char[ ] un {c,h,a,t} : comment et pourquoi bien nommer ses variables en codant ? (1/2)



La communication est la clé de la réussite d’un projet. Dans une équipe de développement cela passe, entre autre, par le code. Partagé par tous les membres de l’équipe, le code doit être facilement compréhensible par tous, nouveaux venus comme "vétérans" du projet. Cette compréhension passe par la mise en place d’un certain nombre de normes à respecter, parmi lesquelles on compte la nomenclature. C’est ce sujet que nous allons aborder dans cet article, et plus précisément les "Meaningful Names".



Objectif


Comme leur nom l’indique, les meaningful names ont pour objectif de donner du sens au code via le nom des variables, des classes et des méthodes. Une variable "theList" par exemple ne porte aucun sens en l’état : on ne sait ni à quoi elle sert, ni ce qu'elle contient. En revanche une variable "commandes" indique qu'il s'agit d'un ensemble cohérent de commandes. Le code doit pouvoir être lu comme des phrases dans la langue choisie par l’équipe de développement. Nous allons vous donner quelques exemples de bonnes pratiques à suivre en termes de nomenclature.



Règle 1 : Encapsuler les valeurs numériques et les chaînes de caractères dans une constante portant un nom significatif


Prenons un exemple de code :



Le code est indenté, avec de l’espace, mais un effort supplémentaire est nécessaire pour comprendre ce qu’il fait. Il y a des valeurs en dur comme "0" ou "4" qui n’ont de sens qu’avec les règles de gestion sous les yeux. Ici, il faut comprendre que l’on souhaite récupérer tous les éléments de notre liste ayant pour valeur "4" pour les ajouter au résultat.

En utilisant des constantes avec un nom adéquat, le code pourrait devenir :





En remplaçant les valeurs numériques par un nom intelligible, la lecture et la compréhension de cet extrait de code en sont facilités, ce qui permet de gagner du temps et d’éviter des erreurs d’interprétation.



Règle 2 : Utiliser des noms de variables explicites ne contenant que des informations pertinentes pour la compréhension.


Utiliser des noms de variables explicites permet de renseigner le lecteur sur l'intention du code.


En reprenant là où nous l'avions laissé le code précédent, les variables "list1", "x", "theList" n’ont pas vraiment de sens et n’apportent pas grand-chose à la compréhension du code. Le lecteur doit connaître le contexte du projet pour comprendre que :

  • theList correspond en réalité à un plateau de jeu modélisé par une liste de cases dont chacune est représentée par une liste de propriétés sous forme de nombre entier

  • x correspond à une case du plateau

  • list1 contient la liste des cases du plateau sur lesquelles se trouvent un pion.

En renommant correctement ces variables, on obtient :



  • cell : permet de renseigner la nature de l'objet que l'on est en train de manipuler, à savoir une case qui est composée d'une liste de propriétés sous forme d'un tableau

  • flaggedCells : Indique clairement l'intention de la variable, c’est-à-dire stocker une liste de d’objets "cell" qui remplissent les critères d’éligibilité.

  • gameBoard : permet de renseigner la nature du paramètre passé en argument, c’est-à-dire un tableau de "cells" représentant le plateau de jeu


Voici une liste d’erreurs communes à proscrire lorsque vous nommez vos variables :

- Utiliser des abréviations (par ex "usr", "cmd", "idx") : les abréviations nuisent à la lisibilité du code : le choix peut être ambigu, induire le lecteur en erreur, et, dans tous les cas oblige le lecteur à un travail intellectuel de conversion chaque fois que l'occurrence apparaît.


- Utiliser des noms de variables trop proches (par ex "SomeVariablesForEfficientHandlingOfStrings" et "SomeVariablesForEfficientStorageOfStrings") : des noms trop semblables sont difficiles à distinguer dans leur utilisation et dans leur sens, ce qui peut favoriser les erreurs d'utilisation par la suite et complexifie la compréhension du code.


- Qualifier ses variables de manière redondante (par ex "commandesList", "usersMap", "modulesTab") : les qualifiers apposés à la suite du nom de la variable n'apportent pas une information pertinente (les IDEs permettent de savoir rapidement de quels types d'implémentation il s'agit). Si l'implémentation change, il faut aussi changer le nom de la variable si on ne veut pas voir apparaître des variables "commandesList" qui sont en réalité des "Map" par exemple.


- Qualifier ses variables de manière neutre (par ex "theList", "aMap", "someElement") : dans le meilleur des cas Il s'agit d'une tentative de réutilisation d'un nom d'une variable existante ("commandes" et "theCommandes"). Si les deux noms sont similaires, c'est que l'on n’a pas réussi à distinguer leur contexte d'utilisation (ou que l'on n'avait pas donné suffisamment de sens à la première variable dès le départ). Cela compliquera la tâche de compréhension du lecteur, voire l'induira en erreur.


- Utiliser des qualifiers numériques (par ex "user1", "user2",…) : les qualifiers numériques permettent au développeur de ne pas avoir à rechercher de nom significatif pour traiter avec deux objets souvent apportés au même niveau (dans les paramètres ou dans une boucle). Dans la suite du code, l'utilisation et le sens de ces objets devient plus difficile à percevoir et peut favoriser les erreurs.


- Utiliser des suffixes qui caractérisent le type d’objet (par ex "userDTO", "userForm", "userPO", "userBean"…) : intégrer le type d'objet au nom de la variable n'apporte pas d'information pertinente pour le code qui exploite l'objet. La plupart du temps, le code ne se préoccupe pas de savoir s'il s'agit d'un ProcessDTO ou d'un ServiceDTO, il fait confiance à l'application pour lui apporter le bon objet qu'il peut ensuite exploiter. Par ailleurs, ces suffixes rendent difficile l'apport d'un contexte à la variable. Une variable "manifestationServiceDTOToDelete" est plus difficile à lire qu'une variable "manifestationToDelete". Dans le cas des classes de transfert qui construisent un objet à partir d'un objet de la classe du dessous, on peut avoir recours à des "From / To". Par exemple : pour construire un ManifestationServiceDTO à partir d'un ManifestationProcessDTO, et puisqu'on ne peut pas les appeler tous les deux "manifestation", on peut mettre "manifestationFromProcess" et "manifestationToService". Inversement, lorsqu'on construit un ProcessDTO à partir d'un ServiceDTO, on peut les nommer "manifestationFromService" et "manifestationToProcess", ce qui permet d'ajouter au contexte des variables le sens de la conversion.


- Utiliser des variables anonymes (par ex "int i", "List<> l", "Map<> m",… ) : ces noms ne portent aucun sens et relèvent dans la plupart des cas d'une simple paresse. Attention également à l’usage du L minuscule et du O majuscule qui peuvent être confondus avec les chiffres 1 et 0 !


- Utiliser des variables neutres (par ex "List<...> list", "Object item", "Object elem", "int number") : ces noms neutres n'apportent aucune lumière sur l'utilisation de la variable. Il s'agit d'une vague tentative pour être plus précis qu'avec une variable anonyme en apportant une information sur la nature de l'objet - nature qui peut évoluer au fil du temps, si bien qu'un nom peut devenir obsolète et dans le pire des cas porter une information fausse (une List<...> list qui se transforme en Map<...> list)


Vous disposez désormais de premières règles de base quant à la façon de nommer vos variables et constantes afin de pouvoir faciliter la communication entre les différents membres de votre équipe. Ce n’est qu’un début, la suite de cet article arrive bientôt !

84 vues0 commentaire

Posts récents

Voir tout