Pourquoi les commentaires « Why Not » sont nécessaires
(buttondown.com)- Les commentaires peuvent utiliser un langage humain plus expressif que les identifiants, ce qui les rend adaptés pour laisser dans le code des options absentes et des alternatives abandonnées
- « comment the why, not the what » est une approche qui consiste à mettre autant d’informations que possible dans les identifiants, mais on observe récemment une tendance à déplacer même les raisons dans de longs noms de fonctions ou de tests
- Dans le build epub de
Logic for Programmers, une implémentation lente remplaçait séquentiellement 16 symboles mathématiques dans chaque chaîne, mais comme il n’y a actuellement que 25 chaînes mathématiques, c’est suffisamment rapide - Ce type de commentaire indique où intervenir plus tard si les chaînes mathématiques passent à plusieurs centaines et créent un goulot d’étranglement dans le build, tout en laissant une trace du fait que le code lent était un compromis délibéré
- Les noms de fonctions ou les tests s’attachent à ce que le code fait réellement ; il est donc difficile de documenter automatiquement les informations négatives portant sur les alternatives non retenues et ce qui n’est pas fait
Les informations que les commentaires expriment plus facilement que le code
- Le code est un langage machine structuré, tandis que les commentaires sont écrits dans un langage humain expressif
- « comment the why, not the what » peut être interprété comme l’idée de mettre autant d’informations que possible dans les identifiants
- Les identifiants s’apparentent à une forme limitée de langage humain intégrée au code ; ils ne peuvent pas contenir tout le « what », même si c’est possible dans de nombreux cas
- On voit de plus en plus l’idée que le « why » peut lui aussi être placé non pas dans des commentaires, mais dans de longs noms de fonctions ou de cas de test
- Les bases de code autodocumentées augmentent généralement leur documentation par l’ajout d’identifiants
- À titre d’exception, il existe des cas où remplacer des commentaires par du logging rend le code plus autodocumenté
Ce que couvrent les commentaires « Why Not »
- Les informations difficiles à exprimer dans le code sont les informations négatives
- Les informations négatives attirent l’attention sur ce qui n’existe pas dans le système et sur les raisons pour lesquelles certaines alternatives n’ont pas été choisies
- Le « why not » laisse une trace des choix que le code ne fait pas et de leurs raisons, plutôt que d’expliquer ce que fait le code
Exemple de remplacement de symboles mathématiques dans un epub
- Dans le build epub de
Logic for Programmers, pour des raisons techniques, les notations mathématiques comme\foralln’étaient pas converties en symboles comme∀ - Pour résoudre ce problème, un script remplaçant directement les tokens dans les chaînes mathématiques par leurs symboles Unicode correspondants a été écrit
- L’implémentation la plus simple consiste à appeler
string = string.replace(old, new)pour chacun des 16 symboles mathématiques nécessaires - Cette méthode est inefficace car elle parcourt chaque chaîne 16 fois, mais traiter les 16 remplacements en un seul passage est plus complexe
- L’essentiel du commentaire laissé est le suivant
- Chaque chaîne est parcourue 16 fois
- Le livre ne contient actuellement que 25 chaînes mathématiques, et la plupart font moins de 5 caractères
- C’est donc toujours suffisamment rapide
- Ce commentaire explique non seulement « pourquoi utiliser du code lent », mais aussi « pourquoi ne pas utiliser du code rapide »
Un panneau indicateur pour les futurs lecteurs
- Même si le code lent ne pose pas de problème immédiat, il peut en poser un plus tard
- Si une future version de
Logic for Programmerscontient plusieurs centaines de chaînes mathématiques, cette étape du build pourrait devenir le goulot d’étranglement de tout le build - Laisser un panneau maintenant permet de savoir immédiatement quelle partie corriger plus tard
- Même si le code continue de fonctionner sans problème, le commentaire préserve le fait que l’auteur avait conscience du compromis
- Deux ans plus tard, en rouvrant
epub_math_fixer.py, il y aura moins besoin de réexaminer si le code lent était dû à l’inexpérience, au manque de temps ou à une erreur - Un commentaire négatif laisse l’information selon laquelle l’implémentation lente était connue, qu’une alternative avait été envisagée et qu’il avait été décidé de ne pas optimiser
Pourquoi il est difficile de remplacer cela par des noms de fonctions et des tests
- Un nom de fonction comme
RunFewerTimesSlowerAndSimplerAlgorithmAfterConsideringTradeOffsest beaucoup trop long et n’explique pas suffisamment le compromis réel - Si le code est optimisé plus tard, il peut falloir changer ce nom à plusieurs endroits
- Le problème plus important est que ce type de nom n’indique pas ce que la fonction fait réellement, ce qui affaiblit au contraire l’autodocumentation
- Les identifiants comme les noms de fonctions et de variables ne peuvent contenir qu’une seule portion d’information
- Il est difficile de mettre simultanément dans un même identifiant « ce que fait la fonction » et « le compromis qu’elle accepte »
Les informations négatives sont aussi difficiles à préserver par des tests
- On pourrait créer un test qui grepe les blocs mathématiques du livre et échoue si leur nombre dépasse 80
- Mais un tel test ne teste pas directement
EpubMathFixerlui-même - À l’intérieur de la fonction, il n’existe pas de point auquel ce test pourrait s’accrocher
- L’autodocumentation se rattache au code écrit et explique ce que fait ce code
- Comme les informations négatives portent sur ce que le code ne fait pas, elles sont fondamentalement incompatibles avec cette approche d’autodocumentation
Une question plus large
- Les commentaires « why not » peuvent être vus comme un exemple de contrefactuel
- Reste la question de savoir si les éléments abstraits de la communication humaine peuvent, de façon générale, être autodocumentés
- Il reste également à savoir si des informations comme les métaphores, l’incertitude ou les arguments éthiques peuvent être autodocumentées
1 commentaires
Avis sur Hacker News
Je me souviens d’une blague que j’ai dû voir sur Twitter il y a quelques années : « un ingénieur junior écrit des commentaires qui expliquent ce que fait le code, un ingénieur intermédiaire écrit des commentaires qui expliquent pourquoi le code fait cela, et un ingénieur senior écrit des commentaires qui expliquent pourquoi le code n’a pas été écrit autrement », quelque chose dans ce genre.
À l’inverse, quand le nom de la fonction et ceux des variables suffisaient à rendre le sens clair, j’ai déjà écrit des fonctions assez grosses sans aucun commentaire.
Donc, oui, moins de commentaires finit par l’emporter, mais quand on voit une base de code sans commentaires, il faut l’examiner directement pour savoir s’il s’agit d’un chef-d’œuvre magnifiquement poli ou d’un code instable produit par des débutants.
Même si cela ressemble à un bricolage complet, c’est parfois réellement le mieux que l’on puisse obtenir.
Si je pense que cela me sera utile quand je relirai le code dans un an, je le laisse en commentaire. En général, c’est le pourquoi et le pourquoi pas ; quand le code est complexe, j’ajoute aussi brièvement le « quoi » pour mieux visualiser le flux.
Ce qui n’est pas utile, ce sont les commentaires obligatoires. Les API publiques doivent être suffisamment documentées, mais certaines organisations imposent des commentaires sur toutes les fonctions, jusqu’aux fonctions private, au point de simplement répéter le nom de la fonction tant son objectif est évident. Non seulement c’est une perte de temps, mais cela rend insensible aux commentaires et apprend à les ignorer.
Je n’aime pas non plus les commentaires inutiles ajoutés par les outils. Mettre
//forou//trysur chaque boucle, par exemple, est particulièrement mauvais.Il vaudrait mieux supprimer les commentaires obligatoires et générés, et, dans les thèmes sombres, afficher les commentaires dans une couleur néon claire pour qu’ils ressortent. Si un commentaire est présent, cela devrait vouloir dire qu’il est important.
Quand on maintient un grand système ancien dans un environnement business aux délais serrés, il faut parfois faire des choses étranges, et dans ce cas il faut expliquer pourquoi.
La grande raison de s’opposer aux commentaires est qu’ils deviennent eux aussi une partie du code et nécessitent de la maintenance. Mais la plupart des gens ne lisent les commentaires que lorsqu’ils sont bloqués, et les éditeurs les grisent aussi, les rendant psychologiquement invisibles. Les commentaires deviennent donc facilement obsolètes.
Je me demande si le contexte destiné au « moi du futur » est aussi utile dans une base de code partagée manipulée par beaucoup de développeurs, ou si c’est une approche qui marche surtout quand seules quelques personnes touchent au code.
J’ai donc ajouté « => yes! » au commentaire existant, et j’ai été reconnaissant à mon moi du passé d’avoir documenté cette question. Au travail, surtout lors de corrections de bugs, je laisse souvent un ou deux commentaires avec un numéro de ticket au-dessus d’un changement qui n’est pas évident.
Le format de commentaire que j’ai préféré laisser dans du code est ce modèle : « DEAR MAINTAINER: ce code est comme ça à cause de [raison]. Si, en essayant de le “corriger”, vous vous rendez compte que c’était une terrible erreur, incrémentez le compteur
total_hours_wasted_here = npour avertir la personne suivante. »Je n’en suis pas l’auteur original, mais je l’ai utilisé avec gratitude une ou deux fois, et c’était amusant de voir un commit d’une seule ligne qui ne faisait qu’incrémenter le compteur.
Un ingénieur plus senior a repris la base de code et a tout « corrigé » en version itérative ; il a essayé de me faire la leçon par e-mail sur les raisons pour lesquelles la récursion était mauvaise, mais son code ne satisfaisait pas réellement toutes les exigences, et il a fini par recréer en pratique ce que j’avais fait avec la récursion.
Plus tard, il s’est excusé pour certaines de ses remarques, mais si j’avais mis ce genre de commentaire tout en haut, on aurait peut-être pu éviter toute l’affaire.
Je suis d’accord pour dire que le titre est ambigu, et c’est ce qui m’a poussé à lire l’article. Personnellement, je préfère globalement écrire peu de commentaires, mais les commentaires explicatifs présentés dans l’article ont clairement de la valeur. C’est un bon rappel : expliquer pourquoi on a fait ainsi, et pourquoi pas autrement.
Cela s’applique particulièrement à son propre code qu’il faudra encore maintenir dans 5, 10 ou 15 ans. Récemment, en relisant le nouveau code d’un collègue, je me suis demandé « pourquoi a-t-il fait comme ça ? », puis j’ai vu que, 10 lignes plus haut, il y avait exactement la même raison que j’avais laissée huit ans auparavant. Ce collègue avait suivi la règle essentielle de la maintenance : faire en sorte que le code ressemble au code existant.
Ce n’est qu’un cas particulier d’un principe plus largement applicable : commenter ce qui est surprenant quand on lit le code
Quand on écrit du code, si l’on se demande constamment « est-ce que je pourrai comprendre ce code plus tard ? » et que l’on répond instinctivement « oui » à chaque fois, on fait preuve d’arrogance et l’on se trompe souvent. Si la réponse est « pas sûr », la question suivante est naturellement « pourquoi ? », et la réponse est précisément ce qu’il faut mettre dans le commentaire
Parfois, la réponse est « parce que le lecteur pourrait se demander pourquoi ce n’a pas été écrit autrement », et c’est le cas particulier dont traite cet article. Mais parfois, c’est « parce que son fonctionnement ou la raison pour laquelle c’est correct ne sont pas clairs », et il faut alors un autre type de commentaire
Cela arrive surtout quand on découpe des chaînes ou qu’on parcourt une structure de données inhabituelle comme étape intermédiaire
Les identifiants permettent d’aller très loin à eux seuls, mais pas jusqu’au bout. Personnellement, j’aime assez exiger des commentaires de documentation de type jsdoc/xmldoc pour les méthodes, variables, champs et paramètres publics
Bien nommer une méthode est important, mais écrire brièvement ce qu’elle fait permet de clarifier davantage les choses, et surtout de faire apparaître des défauts évidents. Souvent, dès qu’on écrit la première phrase, un meilleur nom vient à l’esprit ; et si des « et » commencent à apparaître dans l’explication, c’est le signe que la méthode fait trop de choses et qu’elle peut être découpée plus logiquement
Il est facile de penser que les propriétés sont tellement évidentes qu’elles n’ont pas besoin de documentation, mais quelque chose comme
/** The API key */ string ApiKey;laisse énormément de choses de côté. On ne sait pas d’où vient cette clé, si elle est destinée uniquement à un usage interne ou échangée avec un système externe, si elle est obligatoire, si elle peut être null ou vide, s’il existe une longueur maximale, ce qui se passe en cas de valeur invalide, ni s’il y a du code ou de la documentation à lire pour en savoir plusPour l’auteur initial, ces informations prennent 1 ou 2 minutes à écrire, mais pour une nouvelle personne, il peut falloir des heures pour les retrouver lorsqu’elle doit modifier ou utiliser le code, ou qu’elle est appelée des années plus tard pour corriger un bug
Quand j’anticipe ce qu’un relecteur trop tatillon risque de dire en code review, j’écris souvent des commentaires du type « X n’a pas été fait à cause de Y ». Le but est de réduire les allers-retours pénibles
Un commentaire du genre « on parcourt chaque chaîne 16 fois, mais le livre ne contient jusqu’ici que 25 chaînes de formules, dont la plupart font moins de 5 caractères, donc c’est suffisamment rapide » a aussi d’autres variantes
Il s’agit d’ajouter un log de debug qui se déclenche lorsque l’entrée devient beaucoup plus grande que les contraintes de conception initiales. Il transmet presque le même message au futur développeur, mais permet de le découvrir plus tôt et de réduire encore le temps de diagnostic et de debugging
Dans un système idéal de logging et d’observabilité, on mesurerait le temps de tous les composants de l’application et on laisserait souvent des informations de debug, mais qui utilise réellement un système aussi parfait ? L’effort le plus important consiste plutôt à ajouter des logs ciblés aux endroits où les performances pourraient se dégrader plus tard, ou qu’on n’a pas eu le temps d’optimiser
Avec le recul, c’est une idée évidente, mais jusqu’ici je laissais plutôt des commentaires aux endroits à revoir plus tard, en espérant m’en souvenir quand les choses tourneraient mal
Quoi qu’en disent les autres, j’écris beaucoup de commentaires et de commentaires de documentation un peu partout dans le code. Mais j’aborde les choses à l’envers : je commence par rédiger grossièrement en commentaires la liste des étapes de l’application, puis, au fil du développement, je découpe les grandes étapes en plus petites, je supprime ou conserve les commentaires initiaux, et je les affine jusqu’à obtenir un algorithme presque terminé.
Comme je code généralement de l’extérieur vers l’intérieur, j’écris aussi le code pendant que je découpe les commentaires. Parfois, je code en bloc, puis j’ajoute ensuite des commentaires au point que la plupart des gens trouveraient ça pénible. Je documente chaque fonction et chaque variable, et même à une fonction
deg_to_rad, j’ajoute"""Converts degrees to radians.""". Le stockage ne coûte pas cher.Je sais que la plupart des gens n’aiment pas ça, mais ça me va. Si ça vous déplaît, vous pouvez les supprimer avec un script ou lors de la revue de code. Malgré tout, je prends bien plus de plaisir à lire mon vieux code que le code de quelqu’un d’autre sans commentaires. En Python, du code boilerplate simple comme une API Flask est en général auto-documenté, mais c’est justement ce genre de boilerplate qui change souvent et qui peut donc recevoir des commentaires importants. Dans le secteur, on réécrit plus souvent entièrement la partie algorithmique.
Je continuerai donc à aimer les commentaires et les commentaires de documentation.
J’aime conceptualiser l’ensemble dans ma tête, et au début je trouve lent d’expérimenter en essayant réellement plusieurs choix de conception. Donc, une fois qu’un choix de conception est arrêté, il faut absolument le documenter. Les autres n’ont pas encore accès à ce qu’il y a dans ma tête.
Pour les détails, je m’attends à ce qu’ils deviennent plus clairs une fois que les autres auront terminé leur propre conceptualisation. Cela dit, si pour une raison quelconque cette conceptualisation ne se fait pas, le code peut devenir plus difficile à lire ; je l’affine donc en plus pour préserver un minimum de lisibilité de base.
Mettre à jour les commentaires devient souvent autant de travail que modifier le code. Donc, en pratique, les commentaires sont généralement des mensonges en attente de le devenir. Au bout du compte, commentaires et code divergent, et cela peut être pire que du code sans commentaires.
Je préfère des tests automatisés qui montrent l’intention. Les tests, en général, ne peuvent pas mentir, sinon on ne les aurait pas mergés. S’il existe un bon ensemble de tests montrant comment le code est censé être utilisé, c’est ce que je veux voir : c’est explicatif et presque garanti d’être vrai.
C’est extrêmement utile quand il faut y revenir cinq semaines plus tard.
Je suis le principe selon lequel « les commentaires sont des excuses adressées à mon futur moi ».
Si le code est étrange ou lent, ou si c’est une partie que j’expliquerais à quelqu’un en disant « c’est un peu bricolé », je laisse généralement un commentaire. Surtout si j’ai déjà essayé de la modifier auparavant, je documente ce qui n’a pas fonctionné ou ce que j’ai corrigé.
Avec ce critère, les commentaires inutiles disparaissent naturellement, et on finit généralement par documenter le pourquoi seulement quand c’est vraiment nécessaire. Essayez pendant un mois environ sur votre propre codebase, et vous verrez ce que ça donne.