Je discute avec mes nouveaux collègues au sujet des commentaires. Nous aimons tous les deux Clean Code , et je suis parfaitement d'accord avec le fait que les commentaires de code en ligne doivent être évités et que les noms de classe et de méthode doivent être utilisés pour exprimer ce qu'ils font.
Cependant, je suis un grand partisan de l’ajout de résumés de classe restreinte qui tente d’expliquer l’objectif de la classe et ce qu’elle représente en réalité, principalement pour faciliter le maintien du modèle de principe de responsabilité unique . Je suis également habitué à ajouter des résumés d'une ligne aux méthodes expliquant ce que la méthode est censée faire. Un exemple typique est la méthode simple
public Product GetById(int productId) {...}
J'ajoute le résumé de méthode suivant
/// <summary>
/// Retrieves a product by its id, returns null if no product was found.
/// </summary
Je crois que le fait que la méthode retourne null devrait être documenté. Un développeur qui souhaite appeler une méthode ne devrait pas avoir à ouvrir mon code afin de voir si la méthode renvoie la valeur null ou lève une exception. Parfois, cela fait partie d'une interface, alors le développeur ne sait même pas quel code sous-jacent est en cours d'exécution?
Cependant, mes collègues pensent que ce type de commentaires est " une odeur de code " et que "les commentaires sont toujours des échecs" ( Robert C. Martin ).
Existe-t-il un moyen d’exprimer et de communiquer ces types de connaissances sans ajouter de commentaires? Depuis que je suis un grand fan de Robert C. Martin, je suis un peu confus. Les résumés sont-ils les mêmes que les commentaires et donc toujours des échecs?
Ce n'est pas une question de commentaires en ligne.
la source
Réponses:
Comme d'autres l'ont dit, il existe une différence entre les commentaires documentant l'API et les commentaires en ligne. De mon point de vue, la principale différence est qu'un commentaire en ligne est lu à côté du code , tandis qu'un commentaire de documentation est lu à côté de la signature de tout ce que vous commentez.
Compte tenu de cela, nous pouvons appliquer le même principe DRY . Le commentaire dit-il la même chose que la signature? Regardons votre exemple:
Cette partie ne fait que répéter ce que nous voyons déjà du nom
GetById
plus le type de retourProduct
. Cela soulève également la question de savoir quelle est la différence entre "obtenir" et "récupérer", et quelle est la différence entre le code de support et le commentaire. C'est donc inutile et légèrement déroutant. Si quelque chose se passe, cela va à l’encontre de la deuxième partie du commentaire qui est réellement utile:Ah! C'est quelque chose que nous ne pouvons absolument pas savoir avec certitude grâce à la signature et qui fournit des informations utiles.
Maintenant, prenez ceci un peu plus loin. Quand les gens parlent de commentaires car le code a une odeur, la question n'est pas de savoir si le code en tant que tel nécessite un commentaire, mais si le commentaire indique que le code pourrait être mieux écrit, pour exprimer les informations qu'il contient. C'est ce que "odeur de code" signifie - cela ne signifie pas "ne faites pas ceci!", Cela signifie "si vous faites cela, cela pourrait être un signe qu'il y a un problème".
Donc, si vos collègues vous disent que ce commentaire sur null est une odeur de code, vous devez simplement leur demander: "D'accord, comment puis-je l'exprimer alors?" S'ils ont une réponse réalisable, vous avez appris quelque chose. Sinon, ça va probablement tuer leurs plaintes mortes.
En ce qui concerne ce cas particulier, on sait généralement que la question du zéro est difficile. Il y a une raison pour laquelle les bases de code sont jonchées de clauses de garde, pourquoi les contrôles nuls sont une condition préalable populaire pour les contrats de code, pourquoi l'existence de null a été qualifiée d '"erreur d'un milliard de dollars". Il n'y a pas beaucoup d'options viables. Une
Try...
convention populaire, cependant, trouvée en C # est la convention:Dans d'autres langues, il peut être idiomatique d'utiliser un type (souvent appelé quelque chose comme
Optional
ouMaybe
) pour indiquer un résultat qui peut être ou ne pas être là:D'une certaine manière, cette position anti-commentaires nous a permis d'arriver quelque part: nous avons au moins cherché à savoir si ce commentaire représente une odeur et quelles alternatives pourraient exister pour nous.
Que nous fait préférer ces sur la signature originale est un tout autre débat, mais nous au moins avoir des options pour exprimer par le code plutôt que des commentaires ce qui se passe quand aucun produit trouvé. Vous devriez discuter avec vos collègues de l’une des options qu’ils jugent meilleures et pourquoi, et nous espérons pouvoir aider à aller au-delà des déclarations dogmatiques générales sur les commentaires.
la source
Linq
-équivalent deTry...
,...OrDefault
qui retournedefault(T)
si la clause conduirait à un résultat vide.TryGetValue
modèle est un moyen raisonnable de faire cela en C #, mais la plupart des langages fonctionnels ont un meilleur moyen de représenter une valeur manquante. Lire plus iciT TryGetValue(params, ref bool success)
pour tout type T ouT TryGetValue(params)
, avec null indiquant l'échec, pour le type T contraint par la classe, mais leTryGetXX
modèle renvoyébool
est incompatible avec la covariance.Optional<Product>
pour indiquer qu'il est possible qu'aucun produit ne soit renvoyé par la méthode.La citation de Robert C. Martin est sortie de son contexte. Voici la citation avec un peu plus de contexte:
(Copié à partir d'ici , mais la citation originale provient de Clean Code: Un manuel de l'artisanat logiciel agile )
Comment cette citation est réduite à "Les commentaires sont toujours des échecs" est un bon exemple de la façon dont certaines personnes vont prendre une citation raisonnable hors de son contexte et la transformer en dogme stupide.
La documentation de l'API (comme javadoc) est censée documenter l'API afin que l'utilisateur puisse l'utiliser sans avoir à lire le code source . Donc, dans ce cas, la documentation devrait expliquer ce que fait la méthode. Vous pouvez maintenant affirmer que "Récupérer un produit par son identifiant" est redondant car il est déjà indiqué par le nom de la méthode, mais les informations
null
pouvant être renvoyées sont définitivement importantes pour la documentation, car elles ne sont en aucun cas évidentes.Si vous souhaitez éviter la nécessité du commentaire, vous devez supprimer le problème sous-jacent (l'utilisation de
null
comme valeur de retour valide) en rendant l'API plus explicite. Par exemple, vous pouvez renvoyer un type deOption<Product>
type, de sorte que la signature de type elle-même communique clairement ce qui sera renvoyé au cas où le produit ne serait pas trouvé.Toutefois, dans tous les cas, il n'est pas réaliste de documenter une API de manière complète uniquement par le biais de noms de méthodes et de signatures de types. Utilisez doc-comments pour toute information supplémentaire non évidente que l'utilisateur devrait connaître. Prenez par exemple la documentation de l'API
DateTime.AddMonths()
dans la BCL:Il est impossible d'exprimer cela en utilisant uniquement le nom de la méthode et sa signature! Bien entendu, la documentation de votre classe n’exigera peut-être pas ce niveau de détail, ce n’est qu’un exemple.
Les commentaires en ligne ne sont pas mauvais non plus.
Les mauvais commentaires sont mauvais. Par exemple, des commentaires qui n'expliquent que ce que l'on peut déduire du code, l'exemple classique étant:
Les commentaires qui expliquent quelque chose qui pourrait être clarifié en renommant une variable ou une méthode ou en restructurant le code, constituent une odeur de code:
C’est le genre de commentaires que Martin a critiqués. Le commentaire est le symptôme d'une incapacité à écrire du code clair - dans ce cas, utiliser des noms explicites pour les variables et les méthodes. Le commentaire lui-même n’est bien sûr pas le problème, c’est que nous avons besoin du commentaire pour comprendre le code.
Mais les commentaires doivent être utilisés pour expliquer tout ce qui n’est pas évident dans le code, par exemple pourquoi le code est écrit d’une certaine manière non évidente:
Les commentaires qui expliquent ce qu'une partie de code trop compliquée fait aussi, c'est une odeur, mais le correctif n'est pas d'interdire les commentaires, le correctif est le correctif du code! Dans le vrai mot, le code compliqué arrive (espérons-le seulement temporairement jusqu'à ce qu'un refactor), mais aucun développeur ordinaire n'écrit du code parfaitement propre la première fois. Lorsque du code compliqué arrive, il est bien mieux d'écrire un commentaire expliquant ce qu'il fait que de ne pas écrire un commentaire. Ce commentaire facilitera également la refactorisation ultérieure.
Parfois, le code est inévitablement complexe. Il peut s’agir d’un algorithme compliqué ou d’un code qui sacrifie la clarté pour des raisons de performances. Encore une fois, les commentaires sont nécessaires.
la source
x++
peut être bon s'il s'agit de quelque chose comme "incrémenter x de un, encapsulant s'il s'agit de UINT32_MAX"; tous ceux qui connaissent les spécifications de langue saura que incrémenter unuint32_t
enveloppera, mais sans le commentaire ne peut pas savoir si cette enveloppe était attendue partie de l'algorithme mis en œuvre.Il existe une différence entre commenter votre code et documenter votre code .
Des commentaires sont nécessaires pour maintenir le code ultérieurement, c'est-à-dire changer le code lui-même.
Les commentaires peuvent en effet être perçus comme problématiques. Le point extrême serait de dire qu'ils indiquent toujours un problème, que ce soit dans votre code (code trop difficile à comprendre) ou dans le langage (langage incapable d'être assez expressif; par exemple, le fait que la méthode ne retourne jamais
null
peut être exprimé) via des contrats de code en C #, mais il n’existe aucun moyen de l’exprimer par le code, disons PHP).La documentation est nécessaire pour pouvoir utiliser les objets (classes, interfaces) que vous avez développés. Le public cible est différent: ce ne sont pas les personnes qui entretiendront votre code et le modifier dont nous parlons ici, mais les personnes qui ont à peine besoin de l' utiliser .
Supprimer de la documentation parce que le code est suffisamment clair est insensé, car la documentation est spécifiquement conçue pour permettre l'utilisation de classes et d'interfaces sans avoir à lire des milliers de lignes de code .
la source
Eh bien, il semblerait que votre collègue lise des livres, prenne ce qu’ils disent et applique ce qu’il a appris sans réfléchir et sans tenir compte du contexte.
Votre commentaire sur le fonctionnement de la fonction doit être tel que vous puissiez jeter le code d’implémentation. J'ai lu le commentaire de la fonction et je peux écrire le remplacement pour l’implémentation, sans que rien ne se passe mal.
Si le commentaire ne me dit pas si une exception est levée ou si la valeur null est renvoyée, je ne peux pas le faire. De plus, si le commentaire ne vous indique pas si une exception est générée ou si la valeur nil est renvoyée, vous devez vous assurer que votre code fonctionne correctement, qu'une exception soit renvoyée ou que la fonction soit renvoyée.
Votre collègue a donc totalement tort. Et allez-y, lisez tous les livres, mais pensez par vous-même.
PS J'ai vu votre ligne "parfois, elle fait partie d'une interface, de sorte que vous ne savez même pas quel code est en cours d'exécution." Même avec les fonctions virtuelles, vous ne savez pas quel code est en cours d'exécution. Pire, si vous écriviez une classe abstraite, il n'y aurait même pas de code! Donc, si vous avez une classe abstraite avec une fonction abstraite, les commentaires que vous ajoutez à la fonction abstraite sont la seule chose qu'un implémenteur d'une classe concrète doit les guider. Ces commentaires peuvent également être la seule chose qui puisse guider un utilisateur de la classe, par exemple si tout ce que vous avez est une classe abstraite et une fabrique renvoyant une implémentation concrète, mais que vous ne voyez jamais le code source de cette implémentation. (Et bien sûr, je ne devrais pas regarder le code source d' une implémentation).
la source
Il existe deux types de commentaires à prendre en compte: ceux visibles par les personnes utilisant le code et ceux utilisés pour générer de la documentation.
Le type de commentaire auquel fait référence Oncle Bob est celui qui n'est visible que par les personnes possédant le code. Ce qu’il préconise, c’est une forme de SEC . Pour une personne qui consulte le code source, le code source doit correspondre à la documentation dont elle a besoin. Même dans le cas où les gens ont accès au code source, les commentaires ne sont pas toujours mauvais. Parfois, les algorithmes sont compliqués ou vous devez comprendre pourquoi vous adoptez une approche non évidente pour que les autres ne cassent pas votre code s'ils tentent de corriger un bogue ou d'ajouter une nouvelle fonctionnalité.
Les commentaires que vous décrivez sont la documentation de l'API. Ce sont des choses visibles par les utilisateurs de votre implémentation, mais qui n'ont peut-être pas accès à votre code source. Même s'ils ont accès à votre code source, ils travaillent peut-être sur d'autres modules et ne consultent pas votre code source. Ces personnes trouveraient utile de disposer de cette documentation dans leur IDE au moment de la rédaction de leur code.
la source
La valeur d'un commentaire est mesurée en valeur des informations qu'il donne moins l'effort nécessaire pour le lire et / ou l'ignorer. Donc si on analyse le commentaire
pour la valeur et le coût, nous voyons trois choses:
Retrieves a product by its id
répète ce que le nom de la fonction dit, donc c'est un coût sans valeur. Il devrait être supprimé.returns null if no product was found
est une information très précieuse. Cela réduira probablement le temps nécessaire aux autres codeurs pour examiner la mise en œuvre de la fonction. Je suis tout à fait certain que cela économise plus de lecture que le coût de lecture présenté. Ça devrait rester.Les lignes
porter aucune information que ce soit. Ce sont des coûts purs pour le lecteur du commentaire. Ils peuvent être justifiés si votre générateur de documentation en a besoin, mais dans ce cas, vous devriez probablement envisager un autre générateur de documentation.
C’est la raison pour laquelle l’utilisation de générateurs de documentation est une idée discutable: ils nécessitent généralement un grand nombre de commentaires supplémentaires ne contenant aucune information ou ne répétant pas la même chose évidente, uniquement dans l’intérêt d’un document soigné.
Une observation que je n'ai trouvée dans aucune des autres réponses:
Même les commentaires qui ne sont pas nécessaires pour comprendre / utiliser le code peuvent être très précieux. Voici un exemple:
Probablement beaucoup de texte, complètement inutile de comprendre / utiliser le code. Cependant, cela explique pourquoi le code a cette apparence. Cela empêchera les gens de regarder le code, se demander pourquoi cela n'a pas été fait de façon évidente, et commencerait à le refactoriser jusqu'à ce qu'ils sachent pourquoi le code a été écrit comme ceci au départ. Et même si le lecteur est assez intelligent pour ne pas passer directement à la refactorisation, il lui reste à comprendre pourquoi le code a la même apparence avant de se rendre compte qu'il devrait au mieux rester tel qu'il est. Ce commentaire pourrait littéralement économiser des heures de travail. Ainsi, la valeur est supérieure au coût.
De même, les commentaires peuvent communiquer les intentions d'un code, plutôt que son fonctionnement. Et ils peuvent peindre la grande image qui est généralement perdue dans les moindres détails du code lui-même. En tant que tel, vous avez raison d’être en faveur des commentaires de classe. J'apprécie le plus les commentaires de classe s'ils expliquent l'intention de la classe, comment elle interagit avec d'autres classes, comment elle est censée être utilisée, etc. Hélas, je ne suis pas un grand auteur de tels commentaires ...
la source
GetById
soulève la question, quelle est id, et aussi, obtenir quoi d'où. Les commentaires sur la documentation doivent permettre à l’environnement de développement d’afficher les réponses à ces questions. À moins que cela ne soit expliqué ailleurs dans les commentaires de module doc, ce serait également un endroit pour dire pourquoi on obtiendrait l'identifiant de toute façon.Le code non commenté est un mauvais code. C'est un mythe répandu (sinon universel) que le code peut être lu de la même manière qu'en anglais, par exemple. Il doit être interprété, et pour tout code, sauf le plus trivial, qui prend du temps et des efforts. De plus, tout le monde a un niveau de capacité différent en lecture et en écriture dans une langue donnée. Les différences entre les styles et les capacités de codage de l'auteur et du lecteur constituent des obstacles importants à une interprétation précise. C'est également un mythe que vous pouvez déduire l'intention de l'auteur de la mise en œuvre du code. D'après mon expérience, il est rarement erroné d'ajouter des commentaires supplémentaires.
Robert Martin et al. considérez cela comme une "mauvaise odeur" car il se peut que le code soit modifié et que les commentaires ne le soient pas. Je dis que c'est une bonne chose (exactement de la même manière qu'une "mauvaise odeur" est ajoutée au gaz domestique pour alerter l'utilisateur des fuites). La lecture des commentaires vous fournit un point de départ utile pour interpréter le code réel. S'ils concordent, vous aurez une confiance accrue dans le code. S'ils diffèrent, vous avez détecté une odeur d'avertissement et devez poursuivre vos recherches. Le remède à une "mauvaise odeur" ne consiste pas à éliminer l'odeur mais à colmater la fuite.
la source
i++; // Adjust for leap years.
Dans certaines langues (F # par exemple), l’ensemble du commentaire / de la documentation peut en réalité être exprimé dans la signature de la méthode. En effet, dans F #, null n'est généralement pas une valeur autorisée, sauf autorisation spécifique.
Ce qui est courant dans F # (et dans plusieurs autres langages fonctionnels), c’est qu’au lieu de null, vous utilisez un type d’option
Option<T>
qui pourrait êtreNone
ouSome(T)
. Le langage le comprendrait alors et vous obligerait (ou vous avertir si vous ne le faites pas) à correspondre dans les deux cas lorsque vous essayez de l'utiliser.Ainsi, par exemple, en F #, vous pourriez avoir une signature qui ressemble à ceci
Et puis ce serait une fonction qui prend un paramètre (un int) et retourne ensuite un produit ou la valeur Aucun.
Et alors vous pourriez l'utiliser comme ça
Et vous obtiendrez des avertissements du compilateur si vous ne correspondez pas aux deux cas possibles. Il n’ya donc aucun moyen d’obtenir des exceptions de référence null (sauf si vous ignorez les avertissements du compilateur), et vous savez tout ce dont vous avez besoin simplement en regardant la signature de la fonction.
Bien entendu, cela nécessite que votre langage soit conçu de cette manière - ce que de nombreux langages courants tels que C #, Java, C ++, etc. ne le sont pas. Cela peut donc ne pas vous être utile dans votre situation actuelle. Mais il est bon (heureusement) de savoir qu’il existe des langages qui vous permettent d’exprimer ce type d’informations de manière statique, sans commentaires, etc. :)
la source
Il y a d'excellentes réponses ici et je ne veux pas répéter ce qu'elles disent. Mais laissez-moi ajouter quelques commentaires. (Sans jeu de mots.)
Les gens intelligents font beaucoup de déclarations - sur le développement de logiciels et de nombreux autres sujets, je suppose - qui sont de très bons conseils quand ils sont compris dans le contexte, mais que les personnes idiotes prennent hors contexte extrêmes ridicules.
L'idée que le code devrait s'auto-documenter est une excellente idée. Mais dans la vraie vie, il y a des limites à l'aspect pratique de cette idée.
L'un des inconvénients est que le langage peut ne pas fournir des fonctionnalités permettant de documenter ce qui doit être documenté de manière claire et concise. À mesure que les langages informatiques s'améliorent, cela devient de moins en moins un problème. Mais je ne pense pas qu'il soit complètement parti. À l'époque où j’écrivais dans assembler, il était logique d’inclure un commentaire du type "prix total = prix des articles non taxables plus le prix des articles taxables plus le prix des articles taxables * taux de taxe". Exactement ce qui était dans un registre à un moment donné n'était pas nécessairement évident. Il a fallu plusieurs étapes pour effectuer une opération simple. Etc. Mais si vous écrivez dans une langue moderne, un tel commentaire serait simplement une reformulation d'une ligne de code.
Je suis toujours ennuyé quand je vois des commentaires du type "x = x + 7; // ajoute 7 à x". Par exemple, wow, merci, si j'avais oublié la signification d'un signe plus qui aurait pu être très utile. Là où je pourrais vraiment être dérouté, c'est de savoir ce qu'est "x" ou pourquoi il était nécessaire d'ajouter 7 à ce moment-là. Ce code peut être auto-documenté en donnant un nom plus significatif à "x" et en utilisant une constante symbolique au lieu de 7. Comme si vous aviez écrit "total_price = total_price + MEMBERSHIP_FEE;", aucun commentaire n'est probablement nécessaire du tout. .
Cela semble bien de dire qu'un nom de fonction devrait vous dire exactement ce que fait une fonction pour que tout commentaire supplémentaire soit redondant. Je garde de bons souvenirs de l'époque où j'ai écrit une fonction qui vérifiait si un numéro d'article se trouvait dans notre table de base de données, renvoyant la valeur true ou false, et que j'avais appelée "ValidateItemNumber". Semblé comme un nom décent. Ensuite, quelqu'un d'autre est arrivé et a modifié cette fonction pour créer également une commande pour l'élément et mettre à jour la base de données, mais n'a jamais changé le nom. Maintenant, le nom était très trompeur. Cela ressemblait à une petite chose, alors qu'en réalité, il en faisait beaucoup plus. Plus tard, quelqu'un a même supprimé la partie sur la validation du numéro d'article et l'a fait ailleurs, mais n'a toujours pas changé le nom. Donc, même si la fonction n’a plus rien à voir avec la validation des numéros d’article,
Mais dans la pratique, il est souvent impossible pour un nom de fonction de décrire complètement ce que la fonction fait sans que le nom de la fonction soit aussi long que le code qui la compose. Est-ce que le nom va nous dire exactement quelles validations sont effectuées sur tous les paramètres? Que se passe-t-il dans des conditions exceptionnelles? Épeler toutes les ambiguïtés possibles? À un moment donné, le nom deviendrait si long qu'il deviendrait confus. J'accepterais String BuildFullName (String name, String lastname) comme signature de fonction décente. Même si cela n’indique pas si le nom est exprimé par "premier dernier" ou "dernier, premier" ou une autre variante, que fait-il si une partie ou les deux parties du nom sont vierges, si elle impose des limites à la longueur combinée et ce qu'il fait si c'est dépassé,
la source