Beaucoup de gens affirment que "les commentaires devraient expliquer" pourquoi ", mais pas" comment "". D'autres disent que "le code devrait être auto-documenté" et les commentaires devraient être rares. Robert C. Martin affirme que (reformulé selon mes propres mots) souvent "les commentaires sont des excuses pour un code mal écrit".
Ma question est la suivante:
Qu'y a-t-il de mal à expliquer un algorithme complexe ou un morceau de code long et alambiqué avec un commentaire descriptif?
De cette façon, au lieu que d'autres développeurs (y compris vous-même) n'aient à lire l'intégralité de l'algorithme ligne par ligne pour comprendre ce qu'il fait, ils peuvent simplement lire le commentaire descriptif convivial que vous avez écrit en anglais simple.
L'anglais est "conçu" pour être facilement compris par les humains. Java, Ruby ou Perl, cependant, ont été conçus pour équilibrer la lisibilité humaine et la lisibilité par ordinateur, compromettant ainsi la lisibilité humaine du texte. Un humain peut comprendre un morceau d'anglais beaucoup plus rapidement qu'il/elle peut comprendre un morceau de code avec la même signification (tant que l'opération n'est pas anodine).
Donc, après avoir écrit un morceau de code complexe écrit dans un langage de programmation partiellement lisible par l'homme, pourquoi ne pas ajouter un commentaire descriptif et concis expliquant le fonctionnement du code dans un anglais convivial et compréhensible?
Certains diront que "le code ne devrait pas être difficile à comprendre", "rendre les fonctions petites", "utiliser des noms descriptifs", "ne pas écrire de code spaghetti".
Mais nous savons tous que cela ne suffit pas. Ce ne sont que des lignes directrices - importantes et utiles - mais elles ne changent pas le fait que certains algorithmes sont complexes. Et donc difficiles à comprendre lors de leur lecture ligne par ligne.
Est-il vraiment si mauvais d'expliquer un algorithme complexe avec quelques lignes de commentaires sur son fonctionnement général? Quel est le problème avec l'explication d'un code compliqué avec un commentaire?
En termes simples:
Conclusion:
S'expliquer est bien, ne pas avoir à le faire est mieux.
Il y a un tas de raisons différentes pour lesquelles le code est compliqué ou déroutant. Les raisons les plus courantes sont mieux traitées en refactorisant le code pour le rendre moins déroutant, et non en ajoutant des commentaires de quelque nature que ce soit.
Cependant, il existe des cas où un commentaire bien choisi est le meilleur choix.
Si c'est l'algorithme lui-même qui est compliqué et déroutant, pas seulement son implémentation - le genre qui est écrit dans des revues mathématiques et auquel on se réfère toujours comme l'algorithme de Mbogo, puis vous mettez un commentaire au tout début de l'implémentation, en lisant quelque chose comme "Il s'agit de l'algorithme de Mbogo pour la réobservation des widgets, décrit à l'origine ici: [URL du papier]. Cette implémentation contient des améliorations apportées par Alice et Carol [URL de un autre document]. " N'essayez pas d'entrer dans plus de détails que cela; si quelqu'un a besoin de plus de détails, il devra probablement lire l'intégralité du document.
Si vous avez pris quelque chose qui peut être écrit sur une ou deux lignes dans une notation spécialisée et que vous l'avez développé dans un grand glob de code impératif, mettre ces une ou deux lignes de notation spécialisée dans un commentaire au-dessus de la fonction est un bon moyen de dire au lecteur ce qu'il est censé faire . Il s'agit d'une exception à l'argument "mais que se passe-t-il si le commentaire n'est plus synchronisé avec le code", car la notation spécialisée est probablement beaucoup plus facile à trouver bugs que le code. (C'est l'inverse si vous avez écrit une spécification en anglais à la place.) Un bon exemple est ici: https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.cpp# 1057 ...
/**
* Scan a unicode-range token. These match the regular expression
*
* u\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?
*
* However, some such tokens are "invalid". There are three valid forms:
*
* u+[0-9a-f]{x} 1 <= x <= 6
* u+[0-9a-f]{x}\?{y} 1 <= x+y <= 6
* u+[0-9a-f]{x}-[0-9a-f]{y} 1 <= x <= 6, 1 <= y <= 6
Si le code est globalement simple, mais contient une ou deux choses qui semblent excessivement compliquées, inutiles ou tout simplement erronées, mais doivent être de cette façon car des raisons, puis vous mettez un commentaire juste au-dessus du bit suspect, dans lequel vous énoncez les raisons . Voici un exemple simple, où la seule chose qui doit être expliquée est pourquoi une constante a une certaine valeur.
/* s1*s2 <= SIZE_MAX if s1 < K and s2 < K, where K = sqrt(SIZE_MAX+1) */
const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size)
abort();
Alors, quel est le problème d'expliquer du code compliqué avec un commentaire?
Ce n'est pas une question de bien ou de mal, mais de la "meilleure pratique", comme défini dans l'article Wikipedia :
Une meilleure pratique est une méthode ou une technique qui a constamment montré des résultats supérieurs à ceux obtenus avec d'autres moyens, et qui est utilisée comme référence.
La meilleure pratique consiste donc à essayer d’améliorer le code en premier et à utiliser l’anglais si ce n’est pas possible.
Ce n'est pas une loi, mais il est beaucoup plus courant de trouver du code commenté qui nécessite une refactorisation que du code refactorisé qui nécessite des commentaires, la meilleure pratique en témoigne.
Un jour viendra où votre beau code parfaitement conçu, bien structuré et lisible ne fonctionnera pas. Ou cela ne fonctionnera pas assez bien. Ou un cas spécial surviendra où cela ne fonctionne pas et doit être ajusté.
À ce stade, vous devrez faire quelque chose qui change les choses pour que cela fonctionne correctement. en particulier dans le cas où il y a des problèmes de performances, mais aussi souvent dans des scénarios où l'une des bibliothèques, API, services Web, gemmes ou systèmes d'exploitation avec lesquels vous travaillez ne se comporte pas comme prévu, vous pouvez finir par faire des suggestions qui ne sont pas nécessairement inélégantes, mais qui sont contre-intuitives ou non évidentes.
Si vous n'avez pas de commentaires pour expliquer pourquoi vous avez choisi cette approche, il y a de fortes chances que quelqu'un à l'avenir (et que quelqu'un soit même vous) regarde le code, voyez comment il pourrait être "corrigé" pour quelque chose de plus lisible et élégant et annule par inadvertance votre correctif, car il ne ressemble pas à un correctif.
Si tout le monde écrivait toujours du code parfait, il serait évident que le code qui semble imparfait contourne une intervention délicate du monde réel, mais ce n'est pas ainsi que les choses fonctionnent. La plupart des programmeurs écrivent souvent du code confus ou quelque peu enchevêtré, donc lorsque nous rencontrons cela, c'est une tendance naturelle à le ranger. Je jure que mon passé est n vrai idiot chaque fois que je lis l'ancien code que j'ai écrit.
Je ne considère donc pas les commentaires comme des excuses pour le mauvais code, mais peut-être comme une explication pour laquelle vous n'avez pas fait la chose évidente. Ayant // The standard approach doesn't work against the 64 bit version of the Frobosticate Library
permettra aux futurs développeurs, y compris votre futur moi-même, de prêter attention à cette partie du code et de tester cette bibliothèque. Bien sûr, vous pouvez également mettre les commentaires dans vos validations de contrôle de source, mais les gens ne les regarderont qu'après que quelque chose s'est mal passé. Ils liront les commentaires du code au fur et à mesure qu'ils changent le code.
Les gens qui nous disent que nous devrions toujours écrire du code théoriquement parfait ne sont pas toujours des gens avec beaucoup d'expérience en programmation dans des environnements réels. Parfois, vous devez écrire du code qui fonctionne à un certain niveau, parfois vous devez interagir avec des systèmes imparfaits. Cela ne signifie pas que vous ne pouvez pas le faire de manière élégante et bien écrite, mais les solutions non évidentes doivent être expliquées.
Lorsque j'écris du code pour des projets de loisir que je sais que personne d'autre ne lira jamais, je commente toujours des parties que je trouve déroutantes - par exemple, toute géométrie 3D implique des mathématiques avec lesquelles je ne suis pas entièrement à l'aise - parce que je sais quand je reviens dans six mois, j'aurai totalement oublié comment faire ce truc. Ce n'est pas une excuse pour un mauvais code, c'est une reconnaissance d'une limitation personnelle. Tout ce que je ferais en le laissant sans commentaire, c'est créer plus de travail pour moi à l'avenir. Je ne veux pas que mon futur moi doive réapprendre quelque chose inutilement si je peux l'éviter maintenant. Quelle valeur cela aurait-il?
Le besoin de commentaires est inversement proportionnel au niveau d'abstraction du code.
Par exemple, le langage d'assemblage est, à des fins pratiques, inintelligible sans commentaires. Voici un extrait de n petit programme qui calcule et imprime les termes de la série Fibonacci :
main:
; initializes the two numbers and the counter. Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
mov ax,'00' ; initialize to all ASCII zeroes
mov di,counter ; including the counter
mov cx,digits+cntDigits/2 ; two bytes at a time
cld ; initialize from low to high memory
rep stosw ; write the data
inc ax ; make sure ASCII zero is in al
mov [num1 + digits - 1],al ; last digit is one
mov [num2 + digits - 1],al ;
mov [counter + cntDigits - 1],al
jmp .bottom ; done with initialization, so begin
.top
; add num1 to num2
mov di,num1+digits-1
mov si,num2+digits-1
mov cx,digits ;
call AddNumbers ; num2 += num1
mov bp,num2 ;
call PrintLine ;
dec dword [term] ; decrement loop counter
jz .done ;
; add num2 to num1
mov di,num2+digits-1
mov si,num1+digits-1
mov cx,digits ;
call AddNumbers ; num1 += num2
.bottom
mov bp,num1 ;
call PrintLine ;
dec dword [term] ; decrement loop counter
jnz .top ;
.done
call CRLF ; finish off with CRLF
mov ax,4c00h ; terminate
int 21h ;
Même avec des commentaires, il peut être assez compliqué de grogner.
Exemple moderne: les regex sont souvent des constructions d'abstraction très faibles (lettres minuscules, nombre 0, 1, 2, nouvelles lignes, etc.). Ils ont probablement besoin de commentaires sous forme d'échantillons (Bob Martin, IIRC, le reconnaît). Voici une expression régulière qui (je pense) devrait correspondre aux URL HTTP (S) et FTP:
^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|m
+il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.
+\,\;\?\'\\\+&%\$#\=~_\-]+))*$
Au fur et à mesure que les langages progressent dans la hiérarchie des abstractions, le programmeur peut utiliser des abstractions évocatrices (nom de variable, noms de fonction, noms de classe, noms de module, interfaces, rappels, etc.) pour fournir une documentation intégrée. Négliger de profiter de cela et utiliser des commentaires pour en parler est paresseux, un mauvais service et irrespectueux envers le responsable.
Je pense à Recettes numériques en C traduites principalement textuellement en Recettes numériques en C++ , que je déduis comme Recettes numériques (en FORTAN), avec toutes les variables a
, aa
, b
, c
, cc
, etc. maintenus à travers chaque version. Les algorithmes étaient peut-être corrects, mais ils n'ont pas profité des abstractions fournies par les langages. Et ils me font chier. Échantillon de n article de Dr. Dobbs - Fast Fourier Transform :
void four1(double* data, unsigned long nn)
{
unsigned long n, mmax, m, j, istep, i;
double wtemp, wr, wpr, wpi, wi, theta;
double tempr, tempi;
// reverse-binary reindexing
n = nn<<1;
j=1;
for (i=1; i<n; i+=2) {
if (j>i) {
swap(data[j-1], data[i-1]);
swap(data[j], data[i]);
}
m = nn;
while (m>=2 && j>m) {
j -= m;
m >>= 1;
}
j += m;
};
// here begins the Danielson-Lanczos section
mmax=2;
while (n>mmax) {
istep = mmax<<1;
theta = -(2*M_PI/mmax);
wtemp = sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi = sin(theta);
wr = 1.0;
wi = 0.0;
for (m=1; m < mmax; m += 2) {
for (i=m; i <= n; i += istep) {
j=i+mmax;
tempr = wr*data[j-1] - wi*data[j];
tempi = wr * data[j] + wi*data[j-1];
data[j-1] = data[i-1] - tempr;
data[j] = data[i] - tempi;
data[i-1] += tempr;
data[i] += tempi;
}
wtemp=wr;
wr += wr*wpr - wi*wpi;
wi += wi*wpr + wtemp*wpi;
}
mmax=istep;
}
}
Comme cas particulier concernant l'abstraction, chaque langue a des extraits de langage idiomatiques/canoniques pour certaines tâches courantes (suppression d'une liste de liens dynamiques en C), et quelle que soit leur apparence, ils ne doivent pas être documentés. Les programmeurs devraient apprendre ces idiomes, car ils font officieusement partie du langage.
Donc, à emporter: le code non idiomatique construit à partir de blocs de construction de bas niveau qui ne peuvent être évités nécessite des commentaires. Et cela est nécessaire WAAAAY moins qu'il ne se passe.
Je ne pense pas qu'il y ait quelque chose de mal avec les commentaires dans le code. L'idée que les commentaires sont en quelque sorte mauvais à mon avis est due à certains programmeurs qui vont trop loin. Il y a beaucoup de mouvement dans cette industrie, en particulier vers des vues extrêmes. Quelque part en cours de route, le code commenté est devenu équivalent à du mauvais code et je ne sais pas pourquoi.
Les commentaires ont des problèmes - vous devez les garder à jour lorsque vous mettez à jour le code auquel ils se réfèrent, ce qui se produit beaucoup trop rarement. Un wiki ou quelque chose est une ressource plus appropriée pour une documentation complète sur votre code. Votre code doit être lisible sans nécessiter de commentaires. Les notes de contrôle de version ou de révision doivent être l'endroit où vous décrivez les modifications de code que vous avez apportées.
Cependant, rien de ce qui précède n'invalide l'utilisation des commentaires. Nous ne vivons pas dans un monde idéal, donc lorsque l'une des situations ci-dessus échoue pour une raison quelconque, je préfère avoir quelques commentaires pour se replier.
Je pense que vous lisez un peu trop ce qu'il dit. Votre plainte comporte deux parties distinctes:
Quel est le problème d'expliquer (1) un algorithme complexe ou (2) un morceau de code long et alambiqué avec un commentaire descriptif?
(1) est inévitable. Je ne pense pas que Martin soit en désaccord avec vous. Si vous écrivez quelque chose comme racine carrée inverse rapide , vous allez avoir besoin de quelques commentaires, même si c'est juste un "piratage de niveau binaire à virgule flottante". Sauf quelque chose de simple comme un DFS ou une recherche binaire, il est peu probable que la personne qui lit votre code ait de l'expérience avec cet algorithme, et je pense donc qu'il devrait y avoir au moins une mention dans les commentaires sur ce que c'est.
Cependant, la plupart du code n'est pas (1). Rarement écrirez-vous un logiciel qui n'est rien d'autre que des implémentations de mutex roulées à la main, des opérations d'algèbre linéaire obscures avec un mauvais support de bibliothèque et de nouveaux algorithmes connus uniquement du groupe de recherche de votre entreprise. La plupart du code se compose d'appels de bibliothèque/framework/API, d'E/S, d'un passe-partout et de tests unitaires.
C'est le genre de code dont Martin parle. Et il répond à votre question avec la citation de Kernighan et Plaugher en haut du chapitre:
Ne commentez pas le mauvais code. Réécrivez-le.
Si vous avez de longues sections alambiquées dans votre code, vous avez échoué à garder votre code propre . La meilleure solution à ce problème n'est pas d'écrire un commentaire d'un paragraphe en haut du fichier pour aider les futurs développeurs à s'y retrouver; la meilleure solution est de le réécrire.
Et c'est exactement ce que Martin dit:
La bonne utilisation des commentaires est de compenser notre incapacité à nous exprimer dans le code ... Les commentaires sont toujours des échecs. Nous devons les avoir parce que nous ne pouvons pas toujours comprendre comment s'exprimer sans eux, mais leur utilisation n'est pas un motif de célébration.
Ceci est votre (2). Martin convient que le code long et alambiqué nécessite des commentaires - mais il met le blâme pour ce code sur les épaules du programmeur qui l'a écrit, pas une idée nébuleuse que "nous savons tous que ce n'est pas suffisant". Il fait valoir que:
Un code clair et expressif avec peu de commentaires est bien supérieur au code encombré et complexe avec beaucoup de commentaires. Plutôt que de passer votre temps à écrire les commentaires qui expliquent le désordre que vous avez fait, passez-le à nettoyer ce désordre.
Qu'y a-t-il de mal à expliquer un algorithme complexe ou un morceau de code long et alambiqué avec un commentaire descriptif?
Rien de tel. Documenter votre travail est une bonne pratique.
Cela dit, vous avez une fausse dichotomie ici: écrire du code propre contre écrire du code documenté - les deux ne sont pas en opposition.
Ce sur quoi vous devez vous concentrer est de simplifier et d'abstraire du code complexe en un code plus simple, au lieu de penser que "le code complexe est bien tant qu'il est commenté".
Idéalement, votre code devrait être simple et documenté.
De cette façon, au lieu que d'autres développeurs (y compris vous-même) n'aient à lire l'intégralité de l'algorithme ligne par ligne pour comprendre ce qu'il fait, ils peuvent simplement lire le commentaire descriptif convivial que vous avez écrit en anglais simple.
Vrai. C'est pourquoi tous vos algorithmes d'API publics doivent être expliqués dans la documentation.
Donc, après avoir écrit un morceau de code complexe écrit dans un langage de programmation partiellement lisible par l'homme, pourquoi ne pas ajouter un commentaire descriptif et concis expliquant le fonctionnement du code dans un anglais convivial et compréhensible?
Idéalement, après avoir écrit un morceau de code complexe, vous devriez (pas une liste exhaustive):
Aucune de ces étapes n'est triviale à faire (c'est-à-dire que chacune peut prendre quelques heures) et les récompenses pour les faire ne sont pas immédiates. En tant que telles, ces étapes sont (presque) toujours compromises (par les développeurs coupant les coins, les gestionnaires coupant les coins, les délais, les contraintes du marché/autres conditions du monde réel, le manque d'expérience, etc.).
[...] certains algorithmes sont complexes. Et sont donc difficiles à comprendre lors de leur lecture ligne par ligne.
Vous ne devriez jamais avoir à vous fier à la lecture de l'implémentation pour comprendre ce que fait une API. Lorsque vous faites cela, vous implémentez du code client basé sur l'implémentation (au lieu de l'interface) et cela signifie que votre couplage de module est déjà tourné en enfer, vous introduisez potentiellement des dépendances non documentées avec chaque nouvelle ligne de code que vous écrivez et ajoutez déjà une dette technique.
Est-il vraiment si mauvais d'expliquer un algorithme complexe avec quelques lignes de commentaires sur son fonctionnement général?
Non, c'est bien. L'ajout de quelques lignes de commentaires n'est cependant pas suffisant.
Quel est le problème avec l'explication d'un code compliqué avec un commentaire?
Le fait que vous ne devriez pas avoir de code compliqué, si cela peut être évité.
Pour éviter un code compliqué, formalisez vos interfaces, dépensez environ 8 fois plus pour la conception d'API que pour l'implémentation (Stepanov a suggéré de dépenser au moins 10 fois l'interface, par rapport à l'implémentation) et commencez à développer un projet en sachant que vous créez un projet, pas seulement en écrivant un algorithme.
Un projet implique la documentation API, la documentation fonctionnelle, les mesures de code/qualité, la gestion de projet, etc. Aucun de ces processus n'est une étape unique et rapide à effectuer (ils prennent tous du temps, nécessitent une réflexion et une planification, et ils nécessitent tous que vous y reveniez périodiquement et que vous les révisiez/complétiez avec des détails).
au lieu que d'autres développeurs (vous y compris) aient à lire l'intégralité de l'algorithme ligne par ligne pour comprendre ce qu'il fait, ils peuvent simplement lire le commentaire descriptif convivial que vous avez écrit en anglais simple.
Je considérerais cela comme un léger abus de "commentaires". Si le programmeur veut lire quelque chose au lieu de tout l'algorithme, alors c'est à cela que sert la documentation de fonction. OK, donc la documentation de la fonction peut réellement apparaître dans les commentaires dans la source (peut-être pour l'extraction par des outils doc), mais bien que syntaxiquement ce soit un commentaire en ce qui concerne votre compilateur, vous devez les considérer comme des choses distinctes avec des objectifs distincts. Je ne pense pas que "les commentaires doivent être rares" est nécessairement destiné à signifier "la documentation doit être rare" ou même "les avis de droit d'auteur doivent être rares"!
Les commentaires dans la fonction sont pour quelqu'un de lire ainsi que le code. Donc, si vous avez quelques lignes dans votre code qui sont difficiles à comprendre et que vous ne pouvez pas les rendre faciles à comprendre, un commentaire est utile pour le lecteur à utiliser comme espace réservé pour ces lignes. Cela pourrait être très utile pendant que le lecteur essaie simplement d'obtenir l'essentiel, mais il y a quelques problèmes:
Il existe des exceptions, mais la plupart des lecteurs devront comprendre le code lui-même. Des commentaires doivent être écrits pour aider cela, pas pour le remplacer, c'est pourquoi il est généralement conseillé que les commentaires disent "pourquoi vous le faites". Un lecteur qui connaît la motivation des prochaines lignes de code a plus de chances de voir ce qu'il fait et comment.
J'oublie où je l'ai lu mais il y a une ligne nette et claire entre ce qui devrait apparaître dans votre code et ce qui devrait apparaître comme un commentaire.
Je pense que vous devriez commenter votre intention, pas votre algorithme . C'est à dire. commentez ce que vous vouliez faire, pas ce que vous faites.
Par exemple:
// The getter.
public <V> V get(final K key, Class<V> type) {
// Has it run yet?
Future<Object> f = multitons.get(key);
if (f == null) {
// No! Make the task that runs it.
FutureTask<Object> ft = new FutureTask<Object>(
new Callable() {
public Object call() throws Exception {
// Only do the create when called to do so.
return key.create();
}
});
// Only put if not there.
f = multitons.putIfAbsent(key, ft);
if (f == null) {
// We replaced null so we successfully put. We were first!
f = ft;
// Initiate the task.
ft.run();
}
}
try {
/**
* If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
* then you are trying to get from your Multiton in your creator.
*
* Cannot check for that without unnecessarily complex code.
*
* Perhaps could use get with timeout.
*/
// Cast here to force the right type.
return (V) f.get();
} catch (Exception ex) {
// Hide exceptions without discarding them.
throw Throwables.asRuntimeException(ex);
}
}
Ici, il n'y a aucune tentative d'indiquer ce que chaque étape effectue, tout ce qu'elle indique est ce qu'elle est supposée faire.
PS: J'ai trouvé la source à laquelle je faisais référence - Coding Horror: Code Tells You How, Comments Tell You Why
Souvent, nous devons faire des choses compliquées. Il est certainement juste de les documenter pour une compréhension future. Parfois, le bon endroit pour cette documentation est dans le code, où la documentation peut être mise à jour avec le code. Mais cela vaut vraiment la peine d'envisager une documentation séparée. Cela peut également être plus facile à présenter à d'autres personnes, notamment des diagrammes, des images en couleur, etc. Alors le commentaire est juste:
// This code implements the algorithm described in requirements document 239.
ou même juste
void doPRD239Algorithm() { ...
Certes, les gens sont satisfaits des fonctions nommées MatchStringKnuthMorrisPratt
ou encryptAES
ou partitionBSP
. Des noms plus obscurs méritent d'être expliqués dans un commentaire. Vous pouvez également ajouter des données bibliographiques et un lien vers un article à partir duquel vous avez implémenté un algorithme.
Si un algorithme est complexe et nouveau et pas évident, il vaut vraiment la peine d'être documenté, ne serait-ce que pour la circulation interne de l'entreprise. Vérifiez le document dans le contrôle de code source si vous craignez qu'il ne se perde.
Il existe une autre catégorie de code qui n'est pas tant algorithmique que bureaucratique. Vous devez configurer des paramètres pour un autre système ou interagir avec les bogues de quelqu'un d'autre:
/* Configure the beam controller and turn on the laser.
The sequence is timing-critical and this code must run with interrupts disabled.
Note that the constant 0xef45ab87 differs from the vendor documentation; the vendor
is wrong in this case.
Some of these operations write the same value multiple times. Do not attempt
to optimise this code by removing seemingly redundant operations.
*/
Mais nous savons tous que cela ne suffit pas.
Vraiment? Depuis quand?
Un code bien conçu avec de bons noms est plus que suffisant dans la grande majorité des cas. Les arguments contre l'utilisation de commentaires sont bien connus et documentés (comme vous vous y référez).
Mais ce sont des directives (comme toute autre chose). Dans les rares cas (selon mon expérience, environ une fois tous les 2 ans) où les choses seraient pires si elles étaient refactorisées en petites fonctions lisibles (en raison de performances ou de besoins de cohésion), allez-y - mettez un long commentaire expliquant ce qu'est réellement la chose faire (et pourquoi vous violez les meilleures pratiques).
Le but principal du code est de commander à un ordinateur de faire quelque chose, donc un bon commentaire ne remplace jamais un bon code car les commentaires ne peuvent pas être exécutés.
Cela étant dit, les commentaires dans la source sont une forme de documentation pour les autres programmeurs (vous y compris). Si les commentaires portent sur des problèmes plus abstraits que ce que le code fait à chaque étape, vous faites mieux que la moyenne. Ce niveau d'abstraction varie selon l'outil que vous utilisez. Les commentaires accompagnant les routines du langage d'assemblage ont généralement un niveau "d'abstraction" inférieur à, par exemple, cet APL A←0⋄A⊣{2⊤⍵:1+3×⍵⋄⍵÷2}⍣{⍺=A+←1}⎕
. Je pense que cela mériterait probablement un commentaire sur le problème qu'il est censé résoudre, hmmm?
Si le code est trivial, il n'a pas besoin de commentaire explicatif. Si le code n'est pas trivial, le commentaire explicatif sera probablement également non trivial.
Maintenant, le problème avec le langage naturel non trivial est que beaucoup d'entre nous ne sont pas très bons pour le lire ou l'écrire. Je suis sûr que vos compétences en communication écrite sont excellentes, mais néanmoins quelqu'un avec une compréhension moindre de la langue écrite pourrait mal comprendre vos mots.
Si vous essayez très fort d'écrire un langage naturel qui ne peut pas être mal interprété, vous vous retrouvez avec quelque chose comme un document juridique (et comme nous le savons tous, ceux-ci sont plus verbeux et difficiles à comprendre que le code).
Le code devrait être la description la plus concise de votre logique, et il ne devrait pas y avoir beaucoup de débat sur la signification de votre code car votre compilateur et votre plateforme ont le dernier mot.
Personnellement, je ne dirais pas que vous ne devriez jamais écrire de commentaire. Seulement, vous devez vous demander pourquoi votre code a besoin d'un commentaire et comment vous pouvez y remédier. Cela semble être un thème commun dans les réponses ici.
Un point non encore mentionné est que parfois commenter précisément ce qu'un code fait peut être utile dans les cas où un langage utilise une syntaxe particulière à des fins multiples. Par exemple, en supposant que toutes les variables sont de type float
, considérez:
f1 = (float)(f2+f3); // Force result to be rounded to single precision
f4 = f1-f2;
L'effet de la conversion explicite d'un float
en float
est de forcer le résultat à être arrondi à une seule précision; le commentaire pourrait donc être vu comme disant simplement ce que fait le code. D'autre part, comparez ce code à:
thing.someFloatProperty = (float)(f2*0.1); // Divide by ten
Ici, le but de la distribution est d'empêcher le compilateur de crier à la manière la plus efficace de calculer avec précision (f2/10) [c'est plus précis que de multiplier par 0,1f, et sur la plupart des machines, c'est plus rapide que de diviser par 10,0f].
Sans le commentaire, une personne qui examinait l'ancien code pourrait penser que la distribution a été ajoutée en croyant à tort qu'elle serait nécessaire pour empêcher le compilateur de pousser des cris et qu'elle n'était pas nécessaire. En fait, la distribution a pour objectif de faire exactement ce que la spécification de langage dit: forcer le résultat du calcul à être arrondi en simple précision même sur des machines où l'arrondi serait plus cher que de conserver le résultat avec une précision plus élevée. Étant donné qu'un transtypage vers float
peut avoir un certain nombre de significations et d'objectifs différents, un commentaire spécifiant quelle signification est destinée dans un scénario particulier peut aider à clarifier que la signification réelle correspond à l'intention.