Billets
Commenter ou ne pas commenter ?
Internet est incontestablement une technologie formidable qui a littéralement propulsé le partage d’information et l’échange d’idées à un niveau jamais atteint auparavant. Néanmoins, cela génère parfois quelques frustrations, comme lorsque nous lisons les propos d’une personne qui alimente une réflexion dont la conclusion est fondamentalement opposée à notre opinion personnelle. Cela génère alors un sentiment d’urgence inextinguible vous poussant à réagir d’une manière ou d’une autre, car vous voilà au fait d’un crime de quasi-lèse-majesté ; quelqu’un, quelque part sur Internet, à tort !
Cette situation je l’ai vécue en lisant un article intitulé: “Stop writing code comments”, dans lequel son auteur construit une plaidoirie visant à tout simplement arrêter d’écrire, voir d’aller jusqu’à supprimer, les commentaires dans les codes source de programmes informatiques. Bien sûr, ce sujet n’est pas nouveau, et j’ai d’ailleurs déjà largement débattu de cette problématique avec de nombreux collègues. Certains d’entre eux sont d’ailleurs largement partisans d’en user au minimum, car ils les voient au mieux comme une perte de temps, au pire comme source de confusion. Mais de là à aller jusqu’à l’apologie de la suppression totale des commentaires, il y a un pas que je ne pensais pas que l’on pouvait franchir.
Même si mon sang ne fit qu’un tour et si je ressentis l’envie furieuse de nier en bloc ce pamphlet qui ne devait être qu’un ramassis d’âneries, je pris quand même la peine d’étudier l’argumentation de ce détracteur. “L’Art de la Guerre” n’enseigne-t-il pas qu’il faut connaitre son ennemi comme soi-même ? Et puis, il faut quand même bien admettre qu’il serait légèrement présomptueux d’affirmer détenir la seule et unique vérité. Si cet auteur nourrit le sentiment que les commentaires dans un programme sont totalement inutiles, ce ressenti doit reposer quelque part sur des critères un minimum objectif. Je pris donc une grande respiration avant de partir à l’attaque de ce billet afin de bien en saisir les tenants et aboutissants.
Je fus dès lors surpris de constater que les éléments de base soutenant son discours étaient tout à fait sensés, mais que c’était plutôt au niveau des recommandations qu’il en déduisait que cela devenait bancal. L’auteur soutient en effet la thèse du code autodocumenté, c’est-à-dire que tout programmeur doit s’efforcer d’écrire le code le plus clair et le plus expressif possible afin d’éviter autant que possible de devoir expliciter ce qu’il réalise. Les noms de chaque variable, classe ou fonction doit ne laisser planer aucun doute sur le but qu’elles desservent. Les fonctions doivent être de petite taille et ne doivent servir qu’un but clairement indiqué par leur nom. Dès que la logique qui l’anime devient trop complexe, une fonction doit être fractionnée en autant de petits morceaux simples, chacun encapsulé dans sa propre routine. Toutes ces règles de bonnes pratiques permettent ainsi de faciliter autant que possible la relecture du code, sa testabilité, ou encore l’aisance avec laquelle quelqu’un pourra plus tard apporter de quelconques modifications.
Je ne peux que souligner ici la pertinence et l’importance de ces propos, car je suis moi-même un fervent partisan soutenant que du bon code ne doit pas seulement faire ce qu’il doit faire; il doit aussi être extrêmement lisible, structuré et modulable, et ce de manière à minimiser autant que possible sa complexité à tous ses niveaux de lecture. J’entends par là que quand vous regardez un morceau du code source, celui-ci doit permettre de réduire autant que possible la charge mentale de travail de celui qui le relit. Étant donné que dans la vie d’un logiciel, son code sera plus souvent relu qu’il n’a été écrit, cela permet de gagner énormément de temps à toutes les étapes de son existence, tout en diminuant drastiquement la probabilité de laisser trainer toutes sortes de bugs.
En fait ce principe va beaucoup plus loin que le débat qui nous occupe sur les commentaires, et je vais me permettre ici une petite parenthèse. Le but premier de l’ingénierie logiciel et de l’écriture de code tient entièrement dans la gestion de la complexité. Et s’il est facile d’oublier ce point lorsque l’on écrit un programme de quelques centaines de lignes de code, il en est tout autre pour des logiciels plus gros ou plus complexes. Beaucoup ont peut-être déjà assisté à la croissance organique de programmes qui, petit à petit, se transformaient en usines à gaz dont plus personne ne maitrisait le fonctionnement intégralement. Et la règle d’or pour lutter contre ce phénomène tient principalement dans la modularisation systématique et hiérarchique de tous les constituants du programme. C’est pour ça que le développement d’un système passe par la conception de différents modules qui sont eux-mêmes décomposés en sous-modules, en classes, puis en fonctions. C’est pour ça qu’il faut passer du temps à concevoir le fonctionnement de ceux-ci à un plus haut niveau d’abstraction avant de les coder, ou encore qu’il faille passer du temps à concevoir des interfaces pour les connecter les uns aux autres. Partout, il faut s’assurer que les différentes parties soient hautement cohérentes les unes avec les autres (elles visent conjointement le même objectif), mais que leurs couplages (c’est-à-dire leurs interactions) soient faibles. Et c’est ainsi seulement qu’il peut être humainement possible de gérer du code dont les effets peuvent s’étaler sur plusieurs ordres de grandeur de complexité, en allant de la manipulation du simple bit jusqu’à des centaines de MB d’information.
Parmi tous les outils qui permettent de confiner la complexité du code à un niveau humainement acceptable, la notion de code autodocumenté doit bien évidemment constituer le fer de lance de l’arsenal du programmeur, et je ne veux aucunement débattre de ce point ici. Mon problème vient de l’étape qui suit et qui consiste alors à diaboliser les commentaires, en niant non seulement leur utilité, mais aussi en affirmant qu’ils génèrent plus de tort que de bien.
Les critiques à l’égard des commentaires, nombreuses et bien connues, sont alimentées par un éternel débat visant à définir la quintessence de ce que devrait être l’art de la conception de logiciels. Nous pouvons par exemple citer le fait que les commentaires rendraient le code plus difficile à lire, car le langage ordinaire est bien moins précis qu’un langage de programmation. Nous pouvons ajouter que le code change sans que personne ne prenne la peine de modifier les commentaires qui l’accompagnent, rendant la lecture encore plus confuse et difficile. Ils s’apparentent alors à une perte de temps inutile, car ils requièrent d’écrire ou de lire deux fois plus d’informations, l’une étant par ailleurs complètement obsolète et fausse. De plus, l’information ultime, celle qui compte vraiment et qui ne ment jamais, se trouve être le code ; pourquoi s’embarrasser alors d’une charge de travail veine et potentiellement nuisible ?
Toutes les embuches que je viens de citer sont effectivement bien réelles, inutile de le nier. Mais ces problèmes n’arrivent que quand les commentaires sont mal utilisés, par des programmeurs inexpérimentés dans l’art de les employer. Et ce n’est pas parce que quelques maladroits se sont déjà blessés avec une pelle ou une pioche qu’il faut considérer ces outils comme le mal absolu. Imaginez la situation:
“Des outils pour creuser un trou ?! Mais vous êtes fous, c’est une source de tracasseries et d’embêtements sans fin. Il faut les manier avec prudence, en prendre soin, sans compter le risque de se blesser. Moi, je vais vous dire, il n’y a aucun trou que je ne puisse creuser avec mes doigts et une cuillère à café. Vous ne me croyez pas, regardez ce trou d’un mètre cube, entièrement réalisé en trois jours avec de l’huile de coude. Alors, rangez-moi vos outils ou autres pelleteuses du diable, un vrai ouvrier n’utilise que ses muscles et la cuillère à café”.
Si vous trouvez mon histoire caricaturale, je m’en vais vous en compter une autre tout à fait vraie cette fois. Plusieurs personnes m’ont déjà affirmé, totalement convaincues, qu’il n’y a aucune situation qui ne puisse pas se déboguer intégralement au printf. Qu’un vrai pur programmeur n’avait pas besoin d’IDE, juste d’un éditeur de texte comme vi et des printf. L’un a même été jusqu’à m’affirmer que la souris était une perte de temps, tout pouvant se réaliser plus vite avec les raccourcis clavier. J’ai toujours été perplexe devant ce genre d’affirmations. La conviction inébranlable avec laquelle ils étaient proférés me faisait même douter de moi-même au début, me laissant croire que c’était moi l’incompétent qui ne comprenait pas comment déboguer un processus multitâches manipulant des structures de données complexes sans utiliser de points d’arrêts, d’outils d’inspection de variables, ou encore de visualisation de la mémoire. Mais la vérité est bien différente, ces personnes ne se sont probablement jamais frottées à des problématiques autres que celles que je considère moi comme enfantines. Je ne veux pas dire par là qu’il ne faut jamais employer de printf, il s’agit d’une option qui est souvent pertinente, ce que je veux dire c’est qu’il existe aussi beaucoup de situations bien plus délicates et qu’il est très naïf de les ignorer.
Les situations citées à titre d’exemples dans l’article bannissant les commentaires sont ainsi du même acabit, c’est-à-dire simplistes. Elles mettent toutes en oeuvre des exemples triviaux en soulignant l’inutilité d’écrire un commentaire du style “The title of the CD” à côté d’une variable s’intitulant “title”, ou encore “This function sends an email” pour une fonction appelée “SendEmail ()”. Je ne dis pas que je ne suis jamais confronté à ce genre de banalités, mais étant plutôt versé sur l’écriture d’algorithmes résolvant des problèmes compliqués, je demeure très perplexe. J’ai ainsi pour habitude de toujours mentionner en commentaire l’intervalle d’acceptabilité ou les unités physiques auxquelles se rapportent des variables modélisant un processus. Cela permet en un coup d’oeil de comprendre que la variable speed s’utilise en m/s et pas en km/h, sans devoir lire une centaine de lignes de code à la recherche d’un indice quelconque. Dois-je dorénavant m’abstenir de ce genre de futilités et ne miser que sur la notion de code autodocumenté ? Dois-je plutôt maintenant changer le nom de ma variable speed en quelque chose de moins prosaïque comme speed_positive_lessthan150_meterbysecond ?
De la même manière, j’essaie toujours de placer un paragraphe résumant les grandes lignes de ce que réalise chaque fonction, en plus de leur donner un nom explicite. La raison est simple, beaucoup d’entre elles sont assez abstraites et ne permettent pas de les résumer en un triplet de mots. Imaginez par exemple que vous codiez une fonction cherchant la racine d’un polynôme en utilisant la méthode itérative de Newton. Il me semble bon dans ce cas de résumer ce que cette fonction réalise, ainsi que de fournir un pointeur éventuel vers quelque information additionnelle. Dois-je dorénavant plutôt renommer ma fonction FindPolynomialRoot () par quelque chose de plus explicite comme FindPolynomialRoot_UseNewtonApproximation_MoreOnWikipedia_Newtons_method () afin d’éviter de recourir à ces commentaires abjects ?
Même si je force un peu le trait (et encore), la réalité est tout autre. Un bon programmeur doit sans cesse trouver le meilleur compromis en se basant sur tous les outils qui peuvent l’aider à gérer la complexité d’un programme. Le code auto-documenté en est un, très important même, mais il est souvent loin d’être suffisant. Méfiez-vous d’ailleurs de tous ceux qui prétendent avoir trouvé le Graal et prônent une politique absolutiste, car la vérité est souvent dans la nuance, jamais dans les extrêmes. Bien utilisé, l’emploi de commentaires peut et doit vous aider à mieux structurer et documenter votre code. Les refuser, comme l’auteur le prétend dans son article en argüant qu’un programmeur n’est pas un documentateur, revient à prétendre qu’aucune autre forme de documentation que le code n’est nécessaire. Exit donc les architectures logicielles, les diagrammes UML, les plans de test, les modélisations détaillées, le pseudocode ou la description des méthodes algorithmiques et mathématiques, tout ce que vous avez à savoir se trouve dans le code. Tant que nous y sommes, peut-être même que pour un pur programmeur, tout ce qu’il y a à savoir se trouve dans le code compilé.
Plus sérieusement, le code ne contient que ce que le compilateur doit savoir, mais certainement pas tout ce que vous, en tant qu’humain, devez savoir. Les commentaires doivent être vus et utilisés comme moyen de documentation intermédiaire entre le code et les autres documents de conception. Ils ne doivent donc pas faire double emploi, mais plutôt apporter un éclairage à un niveau d’abstration plus élevé, c’est à dire à niveau qu’aucun code auto-documenté ne pourrait atteindre. Les commentaires doivent toujours décrire l’intention du programmeur, et certainement pas reformuler ce que le code réalise. Ils ne doivent dès lors aucunement être redondants et certainement pas être obsolètes. Car oui, les commentaires doivent s’écrire conjointement avec le code lui-même, et changer l’un revient à changer l’autre. Pour bien fixer les idées, dites-vous qu’une ne lisant que les commentaires se rapportant à une fonction, vous devez être non seulement capable de savoir ce que la fonction fait, mais aussi de saisir les grandes lignes logiques de comment elle y parvient. En ce sens, les commentaires doivent toujours décrire une histoire qu’il doit être possible de lire en ignorant le code avec lequel ils s’entremêlent. Des commentaires de plus haut niveau peuvent également aider à comprendre comment l’ensemble des fonctions ou classes s’articulent, en résumant le fonctionnement général ou en ponctuant certaines parties du code, tout comme une table des matières et des titres de chapitre structurent un livre. Et si vous n’avez jamais ressenti le besoin d’employer des commentaires, peut-être est-ce tout simplement parce que vous n’avez jamais écrit de livre. Il n’y a rien de péjoratif là-dedans, mais c’est bon de le savoir avant de prétendre avoir tout compris et militer pour leur disparition.
Pour clore ce petit billet, je voudrais citer le livre “Code Complete” de Steve McConnel. Unique en son genre, ce dernier aborde en long et en large le sujet trop souvent ignoré de la gestion de la complexité dans les programmes informatiques. Et si vous ne deviez en lire qu’un passage, alors il s’agit sans conteste de “The Commento” que vous trouverez chaptire 32.3.