Blog Arolla

Nommer le code

dés de génération de noms arolla
Une fois les blagues éculées mises de côté, il n'y a finalement qu'une difficulté principale universelle en informatique : nommer les choses. Nommer, c'est modéliser, c'est le cœur de notre métier. C'est effectivement difficile, et sujet à discussions sans fin. Et heureusement, parce que c'est ce qui nous rend difficilement remplaçables par des robots. Je vais lister ici quelques heuristiques de nommage qui me sont propres, et que je ne vois pas forcément souvent dans la nature.

Portée du nommage

Nommer les choses sert à les distinguer. S'il n'y avait qu'une chose dans l'univers, nommer n'existerait pas.

Nommer sert à distinguer les choses dans un contexte. Nous n'avons pas besoin de distinguer les choses au-delà du contexte dans lequel on les considère. Dans une pièce, on peut parler de la table sans avoir besoin de la distinguer de toutes les autres tables du monde. La discussion permet également de savoir qu'on parle du meuble, et pas de la table des matières du livre posé dessus, ou de la table de Mendeleïev épinglée au mur.

Si on ramène ça au code, ça veut dire qu'on n'a besoin de distinguer les noms que dans leur espace de nommage. La variable i est parfaitement valable dans une petite boucle. On n'a pas besoin de distinguer une variable d'une fonction de toutes les variables de toutes les fonctions.

Je vais ici introduire la notion de scanabilité que j'ai découverte via Geepaw Hill. Pour faire court, on passe la majorité de notre temps à lire le code. Et en particulier, à trouver l'endroit où le code a l'impact que l'on cherche. Parmi toutes les idées que peut couvrir le terme de lisibilité, j'essaie donc d'optimiser le code pour que les devs trouvent rapidement où le code fait telle ou telle chose. On doit pouvoir le lire en diagonale, rentrer récursivement dans ses sous-parties de manière efficace et efficiente, pour trouver l'impact que l'on cherche.

En particulier, le code doit se lire le plus naturellement possible, raconter une histoire, avec des phrases et des mots simples, des paragraphes courts, dans les termes du métier.

Comme on aime le code scanable, et donc les noms courts, on essaye de ne pas leur ajouter de détails qui ne seraient pas nécessaires à leur distinction au sein du contexte auquel ils sont limités.

Corollaire: plus le contexte d'un nom est petit, plus le nom est court. Plus le contexte est gros plus le nom est long.

Corollaire: plus le contexte d'un nom grossit, plus il faut allonger le nom. Plus on limite le contexte, plus on raccourcit le nom. C'est la raison pour laquelle il faut repenser le contenu d'un morceau de code dont on modifie la portée, et en particulier tous les noms qu'il contient, qu'il expose, ou avec lesquels il interagit.

Par exemple, une variable i dans une boucle peut devenir rowIndex et columnIndex dans deux boucles imbriquées, voire deux champs d'une classe Coordinates quand les variables atteignent un champ de la classe.

Par exemple, une classe peut s'appeler RandomLoadBalancingStrategy parce qu'elle a besoin de se distinguer globalement de RoundRobinLoadBalancingStrategy, ou de RandomNamingStrategy. Mais localement, dans le load balancer, nommer la variable strategy est suffisant une fois la stratégie sélectionnée.

Noms du métier

On aimerait que tous les noms permettent de deviner à quoi correspond le nom d'une chose, par association culturelle ou synesthétique. Mais beaucoup de noms sont arbitraires. Par ex, on sait ce qu'est un chat ou chien, alors que ces mots n'ont rien à voir avec les sons ou apparences de ces animaux.

On essaie d'utiliser les mots du domaine dans le code. Mais il arrive qu'on ait besoin de termes supplémentaires. En particulier, on mappe souvent des mots comme groupe, catégorie, espace, ensemble, liste, etc… sur des dimensions très précises du métier ou des solutions techniques qu'on implémente. Or, à mon sens, rien d'objectif ne permet de distinguer ces mots en dehors du contexte. La convention l'emporte sur le sens. Et c'est très bien comme ça, parce que le jargon a une grande valeur dans la compréhension mutuelle au sein d'un groupe.

Attention toutefois quand le jargon propre à un groupe est utilisé avec le reste du monde. Les conventions deviennent alors néfastes si elles ne sont pas explicitées.

Par exemple, chaque équipe a une définition différente de ce qu'est le rôle de BA. Supposons que, pour l'équipe tigre, les BAs sont des testeurs. Pour l'équipe lego, les BAs sont des experts métiers qui participent à la distillation des cas d'utilisation. Chaque équipe a son jargon. Si les deux équipes doivent collaborer, et donc clarifier leur protocole de collaboration, il y aura beaucoup d'incompréhension tant que le concept de BA n'a pas été explicité.

Nommage par le contrat ou le contenu

On peut nommer des morceaux de code en fonction:

  • De ce qu'ils font, c'est-à-dire de leur contenu. Par exemple, saveIfNotExists, ou persistIfValid
  • Des raisons pour lesquelles on veut les utiliser. Par ex, persist ou add

Je préfère de loin la 2ème option. Déjà parce qu'elle a tendance à donner des noms plus courts, comme mon exemple malhonnête le montre de manière indiscutable. On pourrait aussi invoquer une règle plus théorique, comme le fait que la diminution du couplage encourage l'encapsulation, et donc que l'appelant n'a pas à connaître le contenu d'un morceau de code.

Mais j'ai surtout cette préférence pour 2 raisons bien plus prosaïques:

  • Le nommage par pourquoi plutôt que par comment a tendance à être plus stable. Il ne change pas (ou moins) en fonction de l'évolution du contenu.
  • En focalisant sur le code appelant pour nommer les choses, on favorise l'histoire racontée par le code, et donc la scanabilité.

Je ne suis pas le seul à avoir cette préférence, mais je ne retrouve pas quel.le héro.ïne m'a fait découvrir ce point de vue. Les indices sont les bienvenus.

Notation hongroise par les frameworks

On voit souvent des conventions de suffixes dans des bases de code. Par ex, dans du code spring, les serveurs REST terminent en Controller, les services, au sens du DDD tactique, en Service, les entités JPA en Entity, les DTO json en DTO, etc. Or ces suffixes font trébucher le scan du code par les humains.

De mon point de vue, ces suffixes s'apparentent à la notation hongroise du IIème millénaire, dans laquelle on ajoutait un préfixe aux variables pour expliciter leur type (s pour string, i pour integer…). Malgré la difficulté de changer ses habitudes, cette notation a disparu au gré des évolutions des langages, des environnements de développement, de la culture, et des compositions d'équipes.

De la même manière, il me semble que l'utilité des suffixes plus modernes est très limitée, typiquement dans un IDE. On pourrait choisir de mettre en valeur d'autres dimensions des choses dans leurs noms, comme leur fiabilité, leur performance. Et ainsi ne pas répéter des informations qu'on a déjà souvent dans le répertoire, l'espace de nommage, la hiérarchie de classe, des tags ou annotations diverses, ou n'importe quelle autre source d'information déjà présente. Si vous suivez mon regard, je suis tourné vers living documentation.

Cette convention découle à mon avis de la façon universelle dont sont écrits les tutoriaux des frameworks à la spring. C'est devenu un réflexe pour tout le monde. Ces suffixes sont sûrement utiles dans certains cas, mais certainement pas dans tous les cas qu'on croise dans la nature.

En général, dans mon code, je n'introduis les suffixes à la hongroise que quand le besoin s'en fait douloureusement sentir, et que je n'ai pas d'alternative pertinente. Et pas avant.

Et ça arrive. Par ex, dans une architecture hexagonale by my book, et malgré le fait que les entités et les modèles métiers soient dans des packages différents, il arrive que les environnements aient du mal à gérer les homonymes. Il faut souvent dédupliquer les noms des classes mappées une pour une, indépendamment de leurs packages. A moins que le métier ou l'architecture nous aient guidé vers des noms naturellement différents, ce qui arrive finalement assez souvent quand le métier percole dans le code.

Comme je code rarement seul, et que les équipes tiennent souvent à une telle convention, je n'ai clairement pas l'intention de me sacrifier pour cette colline. On a généralement des priorités bien plus importantes en termes d'évolution des points de vue.

Enfin, j'essaie d'éliminer les termes qui ne veulent rien dire d'autre que « je n'ai pas pris le temps de trouver un nom », comme tools, utils, ou tous les autres noms des sarcastiques et géniaux dés arolla. Quand on croise ces termes dans un nom, on réalise presque toujours qu'on peut simplement les supprimer, sans changer le sens.

Et quand on croise un IUtilsManagerTools, qu'on peut donc remplacer par rien, il est vraiment temps de se poser des questions. Bien entendu, ce commentaire s'effondre si on a posé des conventions fortes, claires, et explicites sur ces termes qui ne peuvent prendre du sens que dans un jargon.

On remballe

Le nommage est une part importante de la modélisation du métier et de l'architecture. C'est également ce qui permet de rendre notre code habitable pour notre futur nous, et les autres. C'est un art délicat, qui nous fait naviguer sur des crètes particulièrement fines et venteuses. Aucune règle n'est absolue. On essaie d'optimiser selon des axes comme la scanabilité du code, la compréhension mutuelle au sein de l'équipe ou avec les utilisateurs, la plasticité du modèle. On itère, on discute, ça dépend™. Mes heuristiques m'aident à prendre des décisions et à structurer les discussions que j'ai avec les équipes.

Et vous, quelles sont vos heuristiques de nommage ?

Plus de publications

Comments are closed.