Journal To comment or not to comment. That is the question.

93
23
avr.
2013

Sommaire

Hier, j'ai participé à une discussion fort intéressante, vis à vis de la nécessité, ou non, de commenter son code. Certains étaient contre, d'autres non.

Voici pourquoi moi je suis pour le fait de commenter, et absolument contre la version courante, mauvais dérivé d'XP et des méthodes agiles qui voudrait faire croire que le code est la documentation, justification au fait de ne pas commenter.

be brave

Tout a commencé par la lecture de cette présentation faite par l'auteur de SQLite, dans laquelle il parle de son code, de comment il le teste, l'écrit, le commente. Bien que datant de 2009, cette présentation est toujours d'actualité et je ne saurais vous conseiller de la regarder. Mais venons en au fait.

Dans cette présentation, il indique que notre cerveau peut être divisé en deux côtés (bon ok, c'est grossier, mais ça fait le job) :

  • un côté plutôt orienté math
  • un côté plutôt orienté langage

Et il estime qu'on pourrait décrire, si on parle de programmation, les deux côtés ainsi :

  • un côté plutôt orienté code
  • un côté plutôt orienté commentaires

Et il y voit une justification au fait de commenter son code :

Why put comments in code ?

  1. Make the code easier to read
  2. Engage the linguistic side of your brain

Et il continue avec le classique « les commentaires ça sert à rien » :

Well written code needs no comments

  • Ignore reason (2) for writting comments
  • No code is ever that well written

Évidemment, dès que j'ai commencé à rapporter ces propos, cette réaction est tout de suite apparue. Mais je pense, réellement, que c'est se tromper. Et que cette présentation à raison.

D'ailleurs, avant d'aller plus loin sur les commentaires, je voudrais vous montrer une petite présentation elle aussi très intéressante. Il s'agit d'une présentation de Laurent Bossavit de l'Institut Agile : « Making sense of Agile design practices ». J'ai d'ailleurs eu la chance d'en voir une version (je crois un peu plus rapide) lors d'un MixIT il y a deux ans. Quoi qu'il en soit, cette présentation s'intéresse aux "bugs" de notre cerveau et montre, comment des pratiques telles que le TDD, le pair programming, nous aident à combattre ses bugs, du type biais de confirmation, effet Dunning-Kruger, etc.

Vous ne croyez pas qu'il existe des bugs dans le cerveau ? Dans ce cas, allez voir cette video. Nan mais vraiment, allez la voir avant de continuer à lire.

Alors, vous l'avez regardée ? Pas mal, non ? Je trouve finalement que ça illustre assez bien le côté cerveau, et aussi évidemment le problème des commentaires.

Bon, évidemment, on ne dit pas qu'il faut commenter tout est n'importe quoi. Les choses triviales ne sont pas à commenter. Ce qui est purement du ressort du langage ne l'est pas non plus. Mais plus important que tout, il faut commenter l'intention. Non pas ce que fait le code mais pourquoi il le fait. Car, parfois, souvent, l'intention ne peut pas être devinée à partir du code.

Voici un exemple. Il n'est probablement pas parfait, mais ça devrait illustrer suffisamment le principe.

Prenez ce code, et expliquez-moi ce qu'il fait. Vous noterez que j'ai même laissé le commentaire d'entête pour aider.

/**
 * The default implementation of the import function.
 * Writes a script tag to
 * import the script.
 *
 * @param {string} src The script source.
 * @return {boolean} True if the script was imported, false
 * otherwise.
 * @private
 */
goog.writeScriptTag_ = function(src) {
  if (goog.inHtmlDocument_()) {
    var doc = goog.global.document;

    if (doc.readyState == 'complete') {
      var isDeps = /\bdeps.js$/.test(src);
      if (isDeps) {
        return false;
      } else {
        throw Error('Cannot write "' + src + '" after document load');
      }
    }

    doc.write(
        '<script type="text/javascript" src="' + src + '"></' + 'script>');
    return true;
  } else {
    return false;
  }
};

Petites aides : c'est un code tiré de Google Closure Library, un framework javascript. inHtmlDocument_ va retourner vrai si on est dans un document html (au contraire d'une appli node.js par exemple). goog.global.document va alors contenir window.document.

Et donc, il sert à quoi ce code ?

Ok, il charge un script, dont l'url est passée en paramètre. Si on est dans une page html. Mais pourquoi si doc.readyState n'est pas complete ? Et pourquoi dans un cas on retourne false et dans l'autre on sort une erreur ?

Comme ça c'est pas évident à trouver, non ?

Maintenant, voyons la version commentée :

/**
 * The default implementation of the import function.
 * Writes a script tag to
 * import the script.
 *
 * @param {string} src The script source.
 * @return {boolean} True if the script was imported,
 *   false otherwise.
 * @private
 */
goog.writeScriptTag_ = function(src) {
  if (goog.inHtmlDocument_()) {
    var doc = goog.global.document;

    // If the user tries to require a new symbol after document
    // load, something has gone terribly wrong. Doing a
    // document.write would wipe out the page.
    if (doc.readyState == 'complete') {
      // Certain test frameworks load base.js multiple times,
      // which tries to write deps.js each time. If that happens,
      // just fail silently. These frameworks wipe the page
      // between each load of base.js, so this is OK.
      var isDeps = /\bdeps.js$/.test(src);
      if (isDeps) {
        return false;
      } else {
        throw Error('Cannot write "' + src + '" after document load');
      }
    }

    doc.write(
        '<script type="text/javascript" src="' + src + '"></' + 'script>');
    return true;
  } else {
    return false;
  }
};

Bon alors, tout d'un coup c'est plus facile, non ? Et pourtant, le code était quand même clair pour n'importe qui connaissant le javascript. Mais rien n'indiquait réellement pourquoi on testait, et ce qu'on en faisait.

Alors, toujours convaincu par le fait que commenter ça ne sert à rien ? Commenter (et je ne parle pas des API) c'est nécessaire. Car le code ne reflète pas nécessairement l'intention. On peut tous comprendre un code, plus ou moins rapidement. Mais comprendre quel était le but est parfois beaucoup, beaucoup plus compliqué sans commentaires. Alors oui, les développeurs n'aiment pas les commentaires. Ils n'aiment pas les écrire, les maintenir. Mais tant pis. Et ne nous planquons pas derrière de fausses excuses pour ne pas commenter, car cela est nécessaire.

Et vous, vous en pensez quoi des commentaires ? Il faut commenter ? Ne pas commenter ? Quoi commenter ?

ps : un subtile clin d'oeil est glissé quelque part, saura-tu le retrouver ?

  • # /* commentaire ou documentation inline ? */

    Posté par  . Évalué à 5.

    Merci pour ce journal bien écrit et équilibré.
    Les commentaires ne sont pas de la documentation, en effet. Mais pourquoi ne pas placer la documentation au plus près du code. Voire dedans, comme Python le permet —avec même la notion de références croisées, même inter-projets.
    Certes, certains langages de programmation sont plus égaux que d'autres en ce qui concerne la documentation, et la mode est au Javascript qui est un vieux langage modernisé, mais toujours pas corrigé pour inclure la documentation —c'est incompréhensible.

    • [^] # Re: /* commentaire ou documentation inline ? */

      Posté par  . Évalué à 7.

      Mais pourquoi ne pas placer la documentation au plus près du code. Voire dedans, comme Python le permet —avec même la notion de références croisées, même inter-projets.

      Par ce que la notion de documentation est très dépendante des projets. Ton idée marche pour les libs et uniquement les libs.

      Autrement je te rejoins que si on ne distingue pas parfaitement 3/4 types de documentations on parle de tout et n'importe quoi et on fait n'importe quoi:

      • Les commentaires: Ils sont là pour aider à lire le code. Leur seule raison d'exister est "pourquoi" et l'intention. Par exemple, ca serait domage de laisser réintroduire des bugs dans une code base qui a été testé pendant des années par ce qu'on n'indique pourquoi on fait ce foutu truc (ah oui c'était une bugfix suite à un BR ouups).
      • Les documents de design: Selon la taille du projet ils sont à écrire ou non. Ca peut aller de 10 lignes dans un readme, à pleins de page pour permettre de comprendre le design général et comment s'y retrouver dans ces 300 modules. Les règles générale, les règles d'interactions etc.
      • La documentation des API: La encore selon ce sur quoi on bosse l'interet varie. Toute API publique doit évidement être parfaitement documentée. Pour les API internes c'est à choisir. Ecrire de la bonne documentation d'API est très couteux, et je constate que si c'est pour de l'interne je n'investi pas assez et donc qu'elle ne sert à rien car extremement redondante avec le code (typage static évidement)
      • La documentation utilisateur: La encore il faut voir en fonction de son produit. Dans la plupart des cas on essayera de faire léger et concis.

      Dans tout les cas celui qui explique que le premier type ne sert à rien est un idiot avec une bonne mémoire qui bosse tout seul et n'a jamais travaillé sur autre chose que son code. Je ne vois pas d'autre explication.

      Par contre il est vrai aussi qu'il faut se forcer pour que son code ait le moins besoin possible d'être commenté. Ca indique qu'il y a le moins de truc chelous ou difficile à intuiter dans le code et l'algo.

      • [^] # Re: /* commentaire ou documentation inline ? */

        Posté par  (site web personnel) . Évalué à 5.

        Je n'aime pas trop le commentaire interne. Cela empêche souvent d'avoir la fonction entière sur un seul écran. Décrire l'intention au dessus de la fonction est pas mal. J'aime bien aussi les microfonctions qui porte le nom de ce qu'elles font même si il s'agit d'une ligne.

        Si un compilateur vérifie le code, très peu vérifie les commentaires (si cela existe : nom de fonction avec erreur, ( ou [ non appairé, etc… ).

        "La première sécurité est la liberté"

        • [^] # Re: /* commentaire ou documentation inline ? */

          Posté par  (site web personnel) . Évalué à 1.

          Je n'aime pas trop le commentaire interne. Cela empêche souvent d'avoir la fonction entière sur un seul écran

          Ton écran fait quelle taille ? ;)

          C'est surtout que ça dépend. Un commentaire au dessus de la fonction pour indiquer les objectifs de la fonction c'est normal. On peut certes y rajouter des informations "générales". Mais les détails doivent être au plus proche du code. Sinon c'est aussi le risque de voir apparaître avec le temps un décalage entre le code et les commentaires (et là ça devient vraiment galère)

          • [^] # Re: /* commentaire ou documentation inline ? */

            Posté par  . Évalué à 9.

            Sinon c'est aussi le risque de voir apparaître avec le temps un décalage entre le code et les commentaires (et là ça devient vraiment galère)

            Je commence à me dire que c'est qu'il faut redécouper la fonction. Je suis pour les commentaires dans les fonctions, mais de plus en plus souvent je me dis que quand tu as un commentaire qui doit décrire une sous partie de ta fonction, c'est que ça doit en être une nouvelle (bonus : tu as un commentaire normalisé (doxygen, javadoc) qui décrit les entrées, les sorties, les cas d'erreur, bonus+ : cette nouvelle méthode deviendra testable unitairement, bonus++ : en plus de ton code, en plus de ton commentaire, tu aura des tests qui décriront son comportement). C'est rébarbatif et comme c'est comme tout il faut pas le respecter pour le respecter, mais plutôt se poser la question.

            Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

            • [^] # Re: /* commentaire ou documentation inline ? */

              Posté par  . Évalué à 5.

              Je commence à me dire que c'est qu'il faut redécouper la fonction. Je suis pour les commentaires dans les fonctions, mais de plus en plus souvent je me dis que quand tu as un commentaire qui doit décrire une sous partie de ta fonction, c'est que ça doit en être une nouvelle

              Mouais, ca depend beaucoup de ce que tu fais. Je bouffe taquet d'ios ces jours (grande nouvelle), c'est pour l'essentiel 90% d'UI, 9% d'appel REST, et 1% de trucs d'informaticien couillu qui ont de la barbe, avec des contraintes de performance assez forte: ca doit etre fluide et leger sur le cpu, meme sur un 3gs d'antan.

              L'ui, pour que ca soit a la fois joli, elegant et rapide, ya pas: c'est long et verbeux. Typiquement, j'ai une classe "Carousel" (le truc ou tu swipes les photos une par une), avec le coeur du machin qui est du layout avec flyweight. Comme on dit par chez moi, ya pas a tortiller du cul pour chier droit, si tu veux faire ca, faut:
              1) prendre l'offset de la scroll view, regarder si t'as deja une tile a cette endroit
              2) si non, en demander une nouvelle, la stocker localement et repartir a 1)
              3) si oui, prendre l'offset de fin, et faire la meme chose que 2, mais a reculons

              Tu tournes le code comme tu veux, ca prend 150 lignes avec commentaires. Une centaine sans. L'essentiel, c'est des calculs de rectangles, sur la stack, et tu vas pas te faire chier a creer des fonctions parce que ca serait decouper just pour le plaisir de decouper, et en pratique ca eloigne juste le code de la ou il devrait etre (sans compter l'overhead de performance sur une fonction qui est appele tres souvent, ca scrolle tres vite une scroll view UIKit. Et oui, j'ai mesure l'impact, il est pas négligeable).
              Et pour etre passer derriere et avoir debugge ce truc, pour finir par "aaaw, fuck it, je vais reprendre tout le code et passer un jour ou deux a tout commenter/documenter", ce qui l'a fait doubler de taille, croit moi t'es tres tres tres content de trouver des commentaires qui expliquent que si ce rectangle la, il a un origin.x qui est inferieur a machin, alors ca veut dire que machin, et que donc tu peux zapper cette tile parce que blabla.
              Et au passage, ca m'a fait corriger qq bugs ( 2-3 edge cases et un de performance ou une collection etait iteree en permanence).

              Des exemples comme ca, j'en ai plein mon code: dimensionnement dynamique + layout avec animations par ci, REST client qui envoye des payload avec 25 champs sur l'objet envoye. J'y peux rien, la nature de la fonction est de faire 150 lignes. Je peux la decouper artificiellement et repasser les parametres calcules aux dites fonctions, mais:
              1) c'est debile
              2) ca rend la comprehension du code vachement plus dur (-doSomething1: (id) param; -doSomething2: (id) param withOtherParam: (id) paramCalculeDansdoSomething1)

              Linuxfr, le portail francais du logiciel libre et du neo nazisme.

              • [^] # Re: /* commentaire ou documentation inline ? */

                Posté par  . Évalué à 7.

                Je présume que j'aurais du mettre dans un nouveau paragraphe ma dernière ligne pour en faire l'emphase. Dans mon idée, il n'y a pas de règles absolue en programmation, il y a des règles que l'on choisi de suivre ou pas et une règle que l'on choisi de suivre, on peut aussi la violer si on a une bonne raison de le faire. Tout ça pour dire que oui des cas particuliers il y en a pleins, ils sont peut être même pas particulier et peut être que c'est le cas général. J'ai dis que je me posais las question. Grosso modo quand je vois un commentaire qui fait plusieurs lignes, je me pose la question d'envoyer le code qui suit dans une fonction.

                Pour ta description en 3 points ça ne veux pas dire grand chose à peu près tout algorithme peut se décrire en quelques points. Ça dépend uniquement du niveau de précision que tu souhaite (et je t'avoue que je n'ai que peut d'idée de la complexité ou non d'un carrousel. Je suis tout de même surpris qu'il n'y ais pas de composant de haut niveau pour faire ça et que tu te retrouve à travailler sur des rectangles, mais c'est peut être une question de performance.

                En parlant de performance quand tu dis que les fonctions consomment des performances, je trouve ça bien dommage, je ne sais pas si c'est un problème du compilateur ou de ton usage de celui-ci, mais l'inlining n'a rien de nouveau et si (dans les langages qui le permettent, je ne sais pas si c'est le cas de l'objective-C) on donne assez d'informations au compilateur, il devrait être capable d'inliner une méthode. Ce qui est dommage c'est que tu te retrouve à viser les performances très (trop à mon avis) tôt dans le développement. Que l'architecture soit pensée pour produire une performance voulue c'est une chose, se poser la question de créer une variable ou devoir inliner à la main (c'est un comble après 60 ans d'avancée dans le domaine de la programmation), c'est à mon avis dommage.

                Bref tu as sans aucun doute raison de faire comme tu fais (je n'en sais rien). Ce que je pense sais qu'avoir des pavés de commentaires au sein d'une fonction indique à minima qu'il y a des blocs de code au quels il faut faire particulièrement attention, ils sont complexes (suffisamment pour mériter d'avoir un bloc de commentaire) et pas testé unitairement (c'est l'ensemble qui l'est). Ce qui implique d'avoir des batteries de tests plus importantes et dont la granularité est plus large.

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                • [^] # Re: /* commentaire ou documentation inline ? */

                  Posté par  . Évalué à 2.

                  En parlant de performance quand tu dis que les fonctions consomment des performances, je trouve ça bien dommage, je ne sais pas si c'est un problème du compilateur ou de ton usage de celui-ci, mais l'inlining n'a rien de nouveau et si (dans les langages qui le permettent, je ne sais pas si c'est le cas de l'objective-C) on donne assez d'informations au compilateur, il devrait être capable d'inliner une méthode

                  Objective c fait du message send, donc pas possible a inliner (le receveur peut forwarder le message a qui il veut ou le mapper sur une autre methode qui lui appartient, c'est plutot pratique quand t'en as besoin).
                  En pratique, un message send dont l'IMP est dans le cache (cas typique quand t'appelle le message 50 fois par seconde comme sur un scroll) est grosso merdo pas loin d'un appel de fonction C.
                  Je peux fourrer tout ca dans une fonction C, mais c'est aussi malin que de faire des classes statiques en Java.
                  Et surtout, ça changera pas grand chose au fait que cette logique appartient a cette methode, n'a rien a faire en dehors et ca ne changera pas le fait que la logique est quand meme a commenter parce qu'elle n'est pas triviale. Casser le truc en fonction va juste rendre le code plus dur a lire, c'est tout.
                  Tu rates completement le point, ce qui est important dans ce cas c'est commenter l'intention et les bugfix qui ont mene a ce code. Que tu mettes le code avant la declaration de la fonction ou dans le body ne change pas grand chose au fait qu'il faut commenter pourquoi c'est comme ca et pas autrement, histoire de confirmer que c'est bien ce que le developeur voulait ecrire en premier lieu.

                  Ce qui est dommage c'est que tu te retrouve à viser les performances très (trop à mon avis) tôt dans le développement

                  Ben ouais, mais t'es marrant toi, j'ai 20ms par run loop, au dela je drop des frames, ce truc est un composant réutilisable donc on peut pas faire les gorets, vu que les gens qui vont l'utiliser vont se retrouver a instancier des vues depuis des .nibs qui vont prendre 5-10ms. Si c'est pour me retrouver avec des scrolls aussi poussif que sous android, je prefere repartir ecrire du code backend, c'est plus marrant.
                  J'ai profile mon truc avant de faire ce genre de choix…

                  Je suis tout de même surpris qu'il n'y ais pas de composant de haut niveau pour faire ça et que tu te retrouve à travailler sur des rectangles, mais c'est peut être une question de performance.

                  Il y en a un, c'est l'UIScrollView (mere de tous), l'UITableView (tres haute performance et robuste comme tout, mais layout purement vertical et avec certaines particularites), et maintenant l'UICollectionView, mais ca c'est iOS6 only. Le probleme est loin d'etre simple a resoudre proprement.

                  Linuxfr, le portail francais du logiciel libre et du neo nazisme.

        • [^] # Re: /* commentaire ou documentation inline ? */

          Posté par  . Évalué à 4.

          Je suis d'accord avec toi, c'est le but. Mais sur une base de code sérieuse même en v1 je n'ai jamais vu un état ou l'on pouvait se passer de commentaires. Ceux qui l'ont fait mentaient, et ceux qui ont maintenu ont pleuré. Après ca doit beaucoup dépendre des domaines et du type de produit. Quand ca peut être simple et évident, aucune raison de faire compliqué.

          Le commentaire interne ca sert à expliquer les cas tordus du fonctionnel ou une approche. Un compilo sérieux aide, mais il reste des choses à expliquer pour aider le lecteur (ou expliquer pourquoi ca a fini comme ca et pas autrement). Exemple à la con, un comportement spécifique à une plateforme qu'on t'a remonté. Si tu ne laisses pas une trace de pourquoi tu fais ca, le lecteur n'a aucune chance de le deviner jusqu'à ce qu'il réintroduise le bug et qu'un nouveau BR arrive.

          Souvent plus une code base à veilli et murri plus il y a des commentaires internes. Car les choses se sont fait affiner et un million de cas tordu sont gérés ce qui n'est pas forcément le cas d'une base neuve. Idem quand tu dois gérer la compatibilité.

    • [^] # Re: /* commentaire ou documentation inline ? */

      Posté par  (site web personnel) . Évalué à 4.

      Merci :)

      Pour ce qui est de mélanger, fusionner documentation et code, il y a aussi tout ce qui tourne autour du literate programming. J'en avais d'ailleurs parlé dans mon De tout, de rien, des bookmarks, du bla bla #10 ainsi que dans un article « Literate programming, pour un code toujours documenté »

      Mais il est vrai que les langages (et les applications) sont plus ou moins facile à écrire de la sorte.

      Quel est le problème pour javascript ? Certe il n'y a pas beaucoup d'outils, mais il y a par exemple YUIDoc de Yahoo!. Ce que je regrette c'est que Google n'ai pas publié l'outil qu'ils utilisent pour Closure. D'autant plus qu'avec cette lib il est nécessaire de bien commenter (les commentaires incluent les notions de typage).

      • [^] # Re: /* commentaire ou documentation inline ? */

        Posté par  . Évalué à 3.

        Sans doute le problème principal avec Javascript est que je le connais mal… et que ce langage est trop laxiste.
        Je trouve étrange de devoir utiliser telle ou telle bibliothèque pour produire du code durable, en fait, plutôt que d'avoir les bonnes pratiques accessibles dès le chargement de l'interpréteur, mais je suis biaisé par Python :-)

        • [^] # Re: /* commentaire ou documentation inline ? */

          Posté par  (site web personnel) . Évalué à 2.

          Hum, quel est le rapport entre trop laxiste et mauvais pour la doc ?

          Après, le fait d'avoir plusieurs libs, ben c'est comme dans tous les langages pour le coup.
          Et il n'est pas obligatoire d'utiliser des libs pour avoir du code durable, je dirais presque que c'est le contraire…

          • [^] # Re: /* commentaire ou documentation inline ? */

            Posté par  . Évalué à 2.

            Je partage ton avis sur le fait qu'utiliser des libs pour des fonctions de base rend le code moins durable, et je n'avais pas vu comment marchait l'outil Yahoo que tu recommandais. Ça rend mon commentaire un peu sans objet :-).
            Par contre il pourrait y avoir une norme claire et officielle sur la façon d'écrire du javascript (et de le documenter), ça ne ferait pas de mal (jshint, jslint…).

          • [^] # Re: /* commentaire ou documentation inline ? */

            Posté par  . Évalué à 5.

            Hum, quel est le rapport entre trop laxiste et mauvais pour la doc ?

            Un exemple: le type statique, contrainte de certains langages, permets de savoir déjà quels types de données une fonction prend en argument. Avec un nom de paramètre lisible, ça épargne dans 95% des cas de mettre le "\param i objet d'entrée correspondant a […]". Exemple: "FooBar nbOccurrences".

      • [^] # Re: /* commentaire ou documentation inline ? */

        Posté par  . Évalué à 6.

        il y a aussi tout ce qui tourne autour du literate programming.

        Par curiosité, pourquoi ne pas pointer vers la page en français ?

        Je suis d'accord que souvent, les pages anglaises sont mieux fournies, mais il manque des choses à la version française ?

        … Bon, je demande parce que c'est mon travail et que j'aimerais qu'il soit reconnu ;-)

        (Pour ma part, quand je fais un lien vers Wikipédia à l'intention de francophone, je compare les deux articles avant de faire le lien.)

        Et s'il y a une vrai raison pour ne pas avoir cité la version française (autre que « Ha oui, tiens, j'avais pas vu »), ça m'intéresse aussi : qu'est-ce qu'il manque ?

        • [^] # Re: /* commentaire ou documentation inline ? */

          Posté par  (site web personnel) . Évalué à 3.

          Bonne remarque :)
          Pourquoi avoir pointé la page anglaise ? Simplement parce que j'ai tapé "wikipedia literate programming" dans Google et j'ai pris le résultat. Vraiment, il n'y a pas d'autre raison, à part le "en général les pages anglaises sont plus détaillées".

          Mais merci de la précision, de pointer la version française :-)

  • # Perl

    Posté par  . Évalué à 5.

    Meme en commentant du Perl, ca t'aidera pas a le relire ! Et puis de toute facon, ce qui est dur a ecrire doit etre dur a lire. Non, mais !

    • [^] # Re: Perl

      Posté par  . Évalué à 10.

      Perl, c'est déjà du "commentaire", cad du texte humain destiné à être exécuté par la machine. C'est juste que certains (humains) ne savent pas lire…

      bon ok -> []

      • [^] # Re: Perl

        Posté par  . Évalué à 2.

        Certes il y a ceux qui ne savent pas lire, mais aussi ceux qui ne savent pas écrire ou s'exprimer correctement.

  • # Commenter l'intention

    Posté par  . Évalué à 6.

    Je suis 100% d'accord avec toi sur le fait de commenter l'intention. J'ai du reprendre en TMA du code qui était passé entre de nombreuses mains, et il était impossible de déterminer si certaines parties du code était buggées ou non : à la lecture, on sait rapidement ce que le code fait, mais on ne sait pas si c'était réellement ce qui était souhaité. Et bien sûr, personne n'avait la réponse…

    On n'a pas tous la même façon de penser, quelque chose qui peut sembler trivial à quelqu'un ne le sera pas forcement pour une autre personne. S'il vous plait, pensez aux personnes qui vont passer derrière vous (hum hum), laissez leur quelques indices … j'en ai marre de d'essayer de deviner le but d'une fonction (et en plus ma boule de cristal ne fonctionne plus).

    • [^] # Re: Commenter l'intention

      Posté par  (site web personnel) . Évalué à 4.

      D'ailleurs, parfois, on peut se rabattre sur le gestionnaire de sources pour glaner des informations. Mais, étrangement, un code non commenté n'aura que très peu de messages de commit parlant…
      J'ai sous les yeux un projet, pendant 2 ans il n'y a eu aucun message de commit. Et très peu de commentaire (pour ne pas dire rien de plus qu'une javadoc automatique). Heureusement pour lui que le dev qui a écrit ça n'est plus ici.

      Mais oui, les commentaires sont aussi (surtout ?) à destination des autres. Point que les gens négligent beaucoup trop, mais plus généralement c'est la question de la maintenance qui est souvent négligée.

      • [^] # Re: Commenter l'intention

        Posté par  . Évalué à 6.

        Souvent déterminer quelle est la bonne documentation est difficile pour le développeur. Après avoir passé pas mal de temps à résoudre un problème épineux, il lui est difficile de déterminer ce qu'il doit dire ; beaucoup de choses lui paraissent évidentes et donc passées sous silence pensant que le code suffit car assez parlant.

        Un bonne pratique peut être d'ajuster les commentaires lors de la revue de code car avec un oeil extérieur…

        • [^] # Re: Commenter l'intention

          Posté par  (site web personnel) . Évalué à 3.

          Un bonne pratique peut être d'ajuster les commentaires lors de la revue de code car avec un oeil extérieur…

          Ca peut être intéressant. A condition que ce soit fait assez rapidement tout de même.
          Mais ça peut être une solution, dans ce cas il faudrait que le commentaire soit justement écris par la personne réalisant la revue (qui n'a donc pas ou moins le côté évident de la résolution)

          Mais d'ailleurs, c'est aussi à rapprocher du pair programming. Car dans ce cas on a deux personnes, travaillant sur le même sujet mais en intervenant différemment. Un peu comme si, pour reprendre la présentation, chacun s'occupait d'un côté du cerveau ;-)

          • [^] # Re: Commenter l'intention

            Posté par  . Évalué à 3.

            Ca peut être intéressant. A condition que ce soit fait assez rapidement tout de même.

            De toute facon la review elle se fait avant d'intégrer ou dans la semaine suivant les commits.

            Mais c'est effectivement un très bon détecteur d'avoir un oeil naïf à côté. Dès qu'on à un doute ca vaut souvent le coup de demander à quelqu'un dans le coin son avis spontanée.

            Mais d'ailleurs, c'est aussi à rapprocher du pair programming.

            Pas d'accord avec ca par contre. Quand tu pair tu ne formes qu'une seule entitée (même si vous ne faites pas la même chose) et tu n'as plus du tout le côté extérieur au problème. Être deux permet d'avoir quelqu'un qui te tape sur les doigts plus facilement et se laisser aller moins facilement, mais on était arrivé à la conclusion qu'il fallait quand même un review par quelqu'un d'extérieur à la tâche.

            Simplement par ce qu'il n'a pas emmagasiné les connaissances de tâche et qu'il va challenger à la fois la solution que son implémentation.

            • [^] # Re: Commenter l'intention

              Posté par  (site web personnel) . Évalué à 3.

              Être deux permet d'avoir quelqu'un qui te tape sur les doigts plus facilement et se laisser aller moins facilement

              Hum, c'est pas tellement la vision que j'en avais…

              Mais oui dans ce cas ce n'est pas le côté extérieur qui est recherché, mais plutôt le fait que les deux personnes ne vont pas penser exactement de la même manière (c'est bien là le but du pair programming). L'un s'attachant plus au code proprement dit, et l'autre plus sur l'intention, les objectifs, la doc justement.
              Et en effet, ça ne remplace pas pour moi une revue de code.

              • [^] # Re: Commenter l'intention

                Posté par  . Évalué à 3.

                Hum, c'est pas tellement la vision que j'en avais…

                C'était une formule. Le fait d'être deux t'aide à ne pas te dire "bon aller c'est pas grave on passe en done et basta" ou "ouai aller ca passe".

                Mais oui dans ce cas ce n'est pas le côté extérieur qui est recherché, mais plutôt le fait que les deux personnes ne vont pas penser exactement de la même manière (c'est bien là le but du pair programming).

                Ca c'est excellent pour la recherche de solution, l'implémentation et le troubleshooting. En effet ca permet de combiner deux approches et donc d'explorer plus large.

                Pour ce dont tu parles ca n'apporte pas grand chose je trouve. Quand tu es deux à avoir passer 3j à troubleshooter un sale problème ou tordu une lib, niveau commentaire je trouve que ca change pas grand chose à si tu étais tout seul. La paire à acquis une connaissance que les autres n'auront pas.

                L'un s'attachant plus au code proprement dit, et l'autre plus sur l'intention, les objectifs, la doc justement.

                Ca c'est très très variable selon sur quoi tu bosses. Personnellement on a jamais suivit une telle organisation. Le pair c'est pour résoudre une tâche. Une fois que la tâche est résolue, un testeur et un relecteur valide le boulot pour avoir d'autres yeux et diffusé la connaissance.

                La valeur de la pair c'est d'avoir deux cervos. Si tu les découpes en ne les faisant pas bosser ensemble tu perds plein de choses je trouve.

              • [^] # Re: Commenter l'intention

                Posté par  (site web personnel) . Évalué à 2.

                Être deux sur un code, ça permet surtout de comprendre ce qu'il est important de commenté car l'autre personne bloque sur les passages "difficiles".
                On retrouve souvent des parties qui ont demandé de la réflexion sur papier pour ensuite se retrouver coder assez simplement.

                La réalité, c'est ce qui continue d'exister quand on cesse d'y croire - Philip K. Dick

        • [^] # Re: Commenter l'intention

          Posté par  . Évalué à 1.

          C'est pour cela que personnellement j'écris généralement le commentaire avant le code. Non seulement, ça m'aide à avoir une bonne vue de ce que je vais faire (et ça fait gagner du temps, après l'écriture du code n'est limitée pratiquement que par la vitesse de frappe), mais aussi ça aide à être pertinent sur les commentaires. Si le problème est vraiment épineux, c'est souvent une mise en mots de ce que j'ai écrit/gribouillé sur ma feuille de papier pour résoudre le problème.
          Après l'écriture de la méthode ou fonction, j'ajuste en ajoutant ce qui pourrait manquer, ou en enlevant ce qui est manifestement en trop.

          Cela me paraît une bonne façon de faire, confirmée par la grande majorité des développeurs expérimentés et bons que je connais, quel que soit le langage ou les techniques utilisées.
          Après un code plus "technique" n'est pas commenté exactement de la même manière qu'un code plus "fonctionnel" mais le principe reste le même.

          • [^] # Re: Commenter l'intention

            Posté par  . Évalué à 3. Dernière modification le 23 avril 2013 à 11:43.

            Tu parles de documentation d'API et non de commentaire. En effet c'est une bonne pratique de savoir exactement ce que ta méthode va faire et comment elle va le faire avant de commencer à l'écrire (cf. "pseudocode programming process" dans l'excellent Code Complete).

            Cependant les commentaires tu ne peux généralement les décider et les écrire correctement qu'une fois que le code existe. Je trouve que la nouvelle classe String de Java est un bon exemple:

            • Le grain des méthodes est bon, le code est simple et se lit naturellement
            • La documentation de l'API est excellente bonne
            • Les commentaires sont présent uniquement lorsqu'il y a besoin de souligner l'intention ou un fait particulier et ne sont absolument pas redondant avec le code.

            C'est assez facile à faire pour des classes simples comme String. Par contre plus ta classe à de métier ou d'interaction avec l'extérieur plus tu vas avoir le logique à expliciter dans le code. Genre ca ou c'est très difficile de garder un code limpide à long terme et ou beaucoup de choses doivent être explicitées.

            • [^] # Re: Commenter l'intention

              Posté par  . Évalué à 1.

              Bon exemple, j'ai envie de dire.

              Il y a bien 3 ou 4 classes (implémentations et déclarations) dans le même fichier de près de 10000 lignes de code, c'est typiquement le genre de situations ou les diagrammes sont utiles, ils permettent au moins de comprendre les relations des classes entres elles.
              C'est aussi le genre de situations ou l'on comprend l'intérêt de séparer implémentations et déclarations, et idéalement ne pas mélanger les classes dans le même fichier.

              Pour le reste, j'ai pas cherché à lire les 10K lignes (sans coloration syntaxique, non merci, et puis j'aime pas cette façon d'indenter :) ), mais vers la fin on voit ceci:

              // Shrink the underlying space
              _virtual_space.shrink_by(bytes);
              
              

              Typiquement le commentaire qui paraphrase le code, que je n'aime pas (j'admets, coup de bol de tomber dessus sur les 10K lignes).
              Bah oui, on se doute que la méthode shrink, elle shrink l'objet sur laquelle on l'appelle. Je dirais même plus, bytes correspond à la nouvelle taille?

              Un peu plus tôt:
              cpp
              // Multi-threaded; use CAS to prepend to overflow list
              void CMSCollector::par_push_on_overflow_list(oop p) {
              NOT_PRODUCT(Atomic::inc_ptr(&_num_par_pushes);)
              assert(p->is_oop(), "Not an oop");
              par_preserve_mark_if_necessary(p);
              oop observed_overflow_list = _overflow_list;
              oop cur_overflow_list;
              do {
              cur_overflow_list = observed_overflow_list;
              if (cur_overflow_list != BUSY) {
              p->set_mark(markOop(cur_overflow_list));
              } else {
              p->set_mark(NULL);
              }
              observed_overflow_list =
              (oop) Atomic::cmpxchg_ptr(p, &_overflow_list, cur_overflow_list);
              } while (cur_overflow_list != observed_overflow_list);
              }

              Notez les noms très explicite: oop, CMSCollector, p. Oui, j'ironise un peu.

              Sur ce coup, le problème de complexité ne viens peut-être pas de la présence/absence de commentaires, mais du fait de tout mettre ensemble dans le même fichier, et de pas avoir de diagramme montrant les relations entre les classes.
              Choses que l'on peut traiter avec les outils appropriés cela dis. J'ai trouvé le code propre d'ailleurs (malgré mon ironie mal placée: oop doit être un type qui décrit une classe, et CMSCollector lié à un CMS, mais vu que je sais pas à quoi sers la lib…).

            • [^] # Re: Commenter l'intention

              Posté par  . Évalué à 0.

              Je suis globalement d'accord avec ce que tu écris, et notamment les exemples qui sont très bons, sauf sur ce point :

              Cependant les commentaires tu ne peux généralement les décider et les écrire correctement qu'une fois que le code existe.
              Je trouve que c'est d'autant plus vrai qu'on maîtrise moins ce que l'on fait. Généralement, plus on maîtrise le sujet traité et les technologies, moins on a besoin d'attendre d'écrire le code pour écrire les commentaires, parce qu'on s'est déjà posé les questions avant d'écrire le code. Quand on découvre des choses en codant (api extérieure au comportement mal maîtrisé, technologies pas assez bien connues…), on est obligé d'écrire des commentaires en codant.
              Après, c'est aussi ma manière de coder et écrire des commentaires, elle me convient très bien :) et le résultat convient à mes collègues quand ils reprennent mon code, c'est l'essentiel.
              On peut aussi préférer écrire code et commentaire en même temps, mais je trouve que ça freine la pensée quand on est vraiment bien concentré sur le code, de devoir en même temps réfléchir à la formulation de ses commentaires, surtout si c'est du code moins technique et plus fonctionnel.

              • [^] # Re: Commenter l'intention

                Posté par  . Évalué à 6. Dernière modification le 23 avril 2013 à 14:34.

                Il faut en effet être nuancé. Une partie des commentaires peuvent être connu avant l'implémentation finale, ce sont les restes du peusdo code quand ils sont nécéssaires. Cependant ce que tu laisseras dépendra du résultat final.

                Après les commentaires sur le code lui même, tu vas t'en rendre compte de leur utilité compte en écrivant. "C'est évident pour moi qu'on n'a pas besoin besoin de tester pour un int overflow mais je le signale au lecteur".

                Après la plupart des commentaires concernent la logique métier et sont ajoutés après la v1 et sont des bugfix et de l'évolution du code. Généralement la v1 est simple et n'a pas besoin de beaucoup de commentaires car elle a été designée de 0 et que le code peut exprimer assez précisément la pensée. Les 10 autres versions après vont rajouter des options, gérer les problèmes de compats, subir du perf tuning, fournir de nouvelle feature etc.

                Bref tu ne mets pas un commentaire pour dire que tu as mal utiliser une lib, c'est débile. Par contre tu laisses des indications comme quoi "On fait ca par ce que": "On attrape cette erreur par ce que sur le système X version Y il peut se produire ca", "On utilise cette option plutôt qu'une autre par que la v21 à un bug", "On ne touche pas a ce pointeur par ce que y'a une action asynchrone qui l'utilise", "On choisi cette approche par ce qu'un utilisateur à rapporter un problème de performance dans la version d'avant", "attention si tu changes cette variable tu changes aussi le comportement de ca" etc. C'est pour ca que les réécritures sont rarement des succès, repartir de 0 ca veut dire remettre sa maturité à 0 et donc perdre son avance.

      • [^] # Re: Commenter l'intention

        Posté par  . Évalué à 4.

        D'ailleurs, parfois, on peut se rabattre sur le gestionnaire de sources pour glaner des informations.

        Le quoi ?

        Ah, le répertoire old qui contient un tas de fichiers souce.old.1, souce.old.42, …

        • [^] # Re: Commenter l'intention

          Posté par  . Évalué à 4.

          Si tu les as dans un autre répertoire avec des numéros ordonnés, tu as encore de la chance.
          Parce que ça pourrait être dans le même répertoire où tu aurais des
          source.old
          source.bak
          source.bak2
          source.bak.bak
          Copie de source
          Copie de source2
          Copie de Copie de source
          source.new (en attendant qu'il prenne la place de source)
          source.new2 (je veux expérimenter autre chose en parallèle)
          source.new-collegue (mon collègue travaille en même temps que moi sur les mêmes sources)

          http://thedailywtf.com/Articles/The_Developmestuction_Environment.aspx

    • [^] # Re: Commenter l'intention

      Posté par  . Évalué à 4.

      c'est vrai qu'un commentaire bien senti aurait permis d'éviter celui-ci :

      /*
      * Don't add uninitialised data.
      MD_Update(&m,buf,j);
      */
      
      
  • # Comment inciter à commenter

    Posté par  . Évalué à 1.

    Il est évident qu'il est nécessaire (indispensable) de commenter son code, de manière à faire apparaître l'intention derrière le code.
    Du coup je trouve que ta question ne se pose pas.
    Si tu le permets, la question qui me semble plus intéressante est : Comment inciter (obliger) les développeurs à commenter leur code de manière pertinente ?

    Certains éditeurs ont bien compris l'enjeu et proposent des métriques de mesure de nombre de lignes de commentaires rapporté au nombre total de lignes de source. Avec une alerte en dessous d'un certain %. Je pense à CAST par exemple.
    Mais bien souvent, ça sert juste à être relu 1 fois tous les 5 ans par un architecte et on n'en tirera rien.

    Côté documentation (et pas commentaire), je trouve que Java a proposé de bonnes pistes :
    - modèle type de documentation : Javadoc
    - IDE générant automatiquement des prototypes de documentation de code
    - mesure de la présence et l'exhaustivité de la documentation dans des outils d'analyse statique (Sonar, checkstyle…)
    L'écosystème propose ce qu'il faut pour mesurer et suivre la qualité de code.
    Par la suite les IDE et outils utilisés dans le monde Java se sont étendus aux autres langages (je pense à Eclipse, Sonar qui sont utilisés sur d'autres langages).
    Doxygen a permis à peu près la même chose que Javadoc mais sans être lié au langage Java.

    Est il possible d'imaginer la même chose avec les commentaires ?
    Actuellement je ne connais pas de meilleur moyen de faire prendre conscience à un développeur qu'il faut commenter que de lui donner à maintenir du vieux code, ayant subi de nombreuses modifications (pas toujours bien commentées).

    • [^] # Re: Comment inciter à commenter

      Posté par  (site web personnel) . Évalué à 5.

      • IDE générant automatiquement des prototypes de documentation de code

      Ca c'est vraiment une fausse bonne idée.
      Il suffit de prendre un code java et de voir le nombre de commentaires autogénérés (et par essence qui ne servent à rien puisque tout l'information provient du code) qui sont laissés tels quels. C'est pire que tout car ça donne l'impression que c'est commenté alors que non.

      Ce qui fait commenter ? Prendre conscience du problème. Comment ? Etre confronté à des vrais problèmes.
      En fait, c'est beaucoup l'expérience. Soit personnelle, soit d'un lead dev (ou autre). Mais bon, c'est plus facile à dire qu'à faire.

      • [^] # Re: Comment inciter à commenter

        Posté par  (site web personnel, Mastodon) . Évalué à 1.

        Ce qui fait commenter ? Prendre conscience du problème. Comment ? Etre confronté à des vrais problèmes.

        Ou alors, avoir risqué d'être confronté aux problèmes, mais d'y avoir échappé grâce à de bons commentaires.

        En effet, avoir trouvé du code bien commenté m'a motivé moi-même à prendre le temps de documenter le mien, parce que je me suis rendu compte que j'avais gagné beaucoup de temps grâce au développeur original du projet.

    • [^] # Re: Comment inciter à commenter

      Posté par  . Évalué à 4.

      Certains éditeurs ont bien compris l'enjeu et proposent des métriques de mesure de nombre de lignes de commentaires rapporté au nombre total de lignes de source.

      C'est totalement débile: vouloir améliorer la qualité en utilisant une métrique quantitative. Tu auras juste beaucoup de commentaires qui ne servent à rien.

      " Individuals and interactions over processes and tools ": remplace ton outil par des relectures pour diffuser le savoir ca sera beaucoup plus efficace. Si tu ne fais pas confiance à ton équipe change l'équipe.

    • [^] # Re: Comment inciter à commenter

      Posté par  . Évalué à 4.

      Pour inciter a bien commenter, le mieux c'est de laisser le développeur passer sur un autre projet pendant 2 ans, et 2 ans après lui demander de reprendre son code.

    • [^] # Re: Comment inciter à commenter

      Posté par  . Évalué à 3.

      Certains éditeurs ont bien compris l'enjeu et proposent des métriques de mesure de nombre de lignes de commentaires rapporté au nombre total de lignes de source. Avec une alerte en dessous d'un certain %

      Ca, c'est assez utile. Perso, j'utilise CCCC pour le C++. Même s'il n'est plus maintenu, il me permets de repérer les parties de code qui ne sont pas commentées, mais aussi et surtout les zones trop complexes.

      IDE générant automatiquement des prototypes de documentation de code

      Beurk.

      Youpi, j'ai une méthode qui AfficherErreur qui prend 3 arguments: int ligne, string fichier et string message . Il va falloir que je dise pour chaque argument ce qu'il fait? Bof bof bof… Simplement mettre "affiche message et l'emplacement d'appel dans le code source (fichier et ligne)" est bien moins pénible et plus clair.

  • # Il y a plusieurs formes de commentaires.

    Posté par  . Évalué à 8.

    Il y a les commentaires définis tels quels par la syntaxe du langage, qui sont selon moi moyennement utiles, et les commentaires implicites: les types des paramètres (et des variables), les noms des classes, des méthodes, des fonctions, des paramètres et des variables.

    Perso, j'ai remarqué que quand une fonction ne fait qu'une chose, elle à tendance à être réellement triviale. Après, il faut que je précise que j'aime C++: typage fort (tant qu'on utilise pas la syntaxe du C, bien sûr) et Orienté Objet, sans imposer ce dernier.

    En général, je maintiens un diagramme des classes, et mes classes sont fortement spécialisées, idem pour les méthodes et fonctions. Du coup, passer les 50 lignes est vraiment une chose rare, d'autant que le moindre duo de ligne qui se ressemble est envoyé dans sa méthode propre.

    Enfin, j'utilise quand même les commentaires explicites, pour préciser les parties des contrats de mes méthodes que je peux pas préciser avec la syntaxe de C++, ainsi que les lignes à la syntaxe barbare (quoique je préfère simplifier ces lignes plutôt que de les commenter).
    Donc, oui, je pense faire du code lisible malgré qu'il soit peu commenté.

    Ce que je n'apprécie pas avec les commentaires, c'est… il faut les maintenir, et ça paraphrase trop souvent le code.
    D'un autre côté, un langage sans typage, je comprend l'intérêt: comment faire pour savoir que tel paramètre est censé ne pas être modifié par la méthode sans typage? Commenter…
    En fin de compte, je pense plus ou moins la même chose des commentaires que de la notation hongroise pour les noms de variables: inutiles avec certains langages/projets, vitaux avec d'autres, et utiles en fonction du degré d'expressivité du langage et de la complexité du projet (un projet avec une grosse contrainte sur la perf, et donc hyper optimisé sera illisible sans commentaires peu importe le langage)

    • [^] # Re: Il y a plusieurs formes de commentaires.

      Posté par  . Évalué à 3.

      Tu sembles te focaliser sur l'aspect technique (le "comment"), alors que tout l'argument en faveur des commentaires est sur le "pourquoi".

      Quelque chose que le code, même super bien écrit, ne permet pas. Et un diagramme de classe n'aide pas nécessairement dans cette optique (mais il est utile pour se forger une vision globale de l'architecture).

      • [^] # Re: Il y a plusieurs formes de commentaires.

        Posté par  . Évalué à 2.

        Je ne suis pas sûr de comprendre ce que tu veux dire?

        Si j'ai une fonction de 50 lignes (j'ai rarement plus) qui s'appelle "printPage(int number)" le pourquoi appeler cette fonction est déjà commenté dans le nom, et on sait que tout ce qu'elle fera sera avec l'objectif d'afficher le contenu de la page number, non?

        Après, logiquement, si tu modifies un programme, tu devrais savoir à quoi il sert, et en creusant couche après couche, si les noms sont corrects (pas toujours simple cela dis) le pourquoi devrait (conditionnel) se situer dans le nommage, pour moi…

        Idem, si tu as une grosse expression type:

        return (x*y+j<2?callFoo(x,y):callBar(j,k);

        Si on y comprend rien c'est clairement parce que les noms sont foireux, et que le développeur à tout mis sur une seule ligne pour rien…

        int FooBarCaller(...)
        {
        int ret;
        if((x*y+j<<k%tmp)>2)
          ret=callFoo(x,y);
        else
          ret=callBar(j,k);
        }
        
        

        Bien que plus lisible, on s'aperçoit encore une fois qu'on ne comprend rien, mais forcément avec des noms à la con… (en même temps, c'est pas un exemple tiré de la vie réelle)

        J'ai un bout de code la (je n'irai pas dire que c'est super propre hein, et c'est de moi il y a quelques mois… :/):

        void Camera::AutoCalibration(void)
        {
        ...
        ...
        ...
            CvRect r; //will contain final values of used rectangle
        ...
        ...
        ...
            if(r.x && r.y && !InsideTolerance(r))
            {
                m_roi=r;
                SetSize(m_roi.width,m_roi.height);
            }
        }
        
        bool Camera::InsideTolerance(CvRect const &target)
        {
            if(m_tolEnabled)
                return CheckSingleTolerance(target.x,m_roi.x,m_tolX)
                    &&CheckSingleTolerance(target.y,m_roi.y,m_tolY)
                    &&CheckSingleTolerance(target.width,m_roi.width,m_tolX)
                    &&CheckSingleTolerance(target.height,m_roi.height,m_tolY);
            return false;
        }
        ...
        ...
        ...
        bool Camera::CheckSingleTolerance(double value, double base, double percent)
        {
            return value*(1+percent)>base && value*(1-percent)<base;
        }
        
        

        1er constat: j'ai un commentaire qui explique le pourquoi de l'existence de la variable "r"… un meilleur nom aurait suffit. Pour m_roi, l'abréviation est un peu plus justifiée, mais pas terrible quand même (RegionOfInterest au cas où. Vu que c'est une classe qui manipule des images prises d'une caméra…).

        2nd constat (où je voulais en venir au final):

        if(r.x && r.y && !InsideTolerance(r))

        ici, "InsideTolerance" ne sers qu'une seule fois dans tout le code, et sert justement à nommer le "pourquoi" de son code.
        Les quelques lignes se traduisent en "si on a des valeurs non-nulles ou en dehors de la zone de tolérance, on les utilise comme nouvelle région d'intérêt.".

        PS:
        Le nommage pourrait vraiment être amélioré d'ailleurs… j'ai limite honte de foutre ça sur un forum… j'aurai aussi du diviser ce bazard en plusieurs classes, rétrospectivement. Pour le coup Camera fait clairement office de fourre-tout, ce qui aide pas du tout à avoir des noms cohérents et clairs: si j'avais encapsulé cette histoire de région dans sa propre classe, avec ses méthodes dédiées donc, l'ensemble aurait été plus simple à lire et comprendre.

        PPS:
        Le code complet de la fonction en question:

        void Camera::AutoCalibration(void)
        {
            if(!m_objectDetect)
                return;
        
            ObjectDetect();
            unsigned short decalX,decalY;
        
            CvRect r; //will contain final values of used rectangle
            r.x=10000;r.y=10000; //dumb values. I should have used a macro like INT_MAX in stdint.h, but VC9 doesn't respect C++03 standard
            r.width=0;r.height=0;
            for( int i = 0; i < m_Objects->total; ++i )
            {
                CvRect rt=GetObjectN(i);
                if( rt.height<= 0 || rt.width<= 0 ||rt.x<= 0||rt.y<= 0 )
                    continue;//!\todo verify that following code (from an example on the web) is not useless
        
                //enlarge rt rectangle with decal values
                decalX=static_cast<unsigned short>(rt.width*m_decalX);
                decalY=static_cast<unsigned short>(rt.height*m_decalY);
                //calculate the final rectangle, which will contain both previous r rectangle and current rt rectangle
                r.x=std::min(rt.x-decalX,r.x);
                r.y=std::min( rt.y-decalY,r.y);
                r.width=std::max(rt.x+rt.width+decalX,r.width);
                r.height=std::max(rt.y+rt.height+decalY,r.height);
            }
        
            //ensure (x,y) contain the lowest coordinates
            if(r.y>r.height)
                std::swap(r.y,r.height);
            if(r.x>r.width)
                std::swap(r.x,r.width);
        
            //transform width and height into dimensions (they are actually coordinates)
            r.width-=r.x;
            r.height-=r.y;
        
            //checking if new roi should be applyed (tolerance and sigsegv fault checks)
            if(r.x && r.y && !InsideTolerance(r))
            {
                m_roi=r;
                SetSize(m_roi.width,m_roi.height);
            }
        }
        
        

        //checking if new roi should be applyed (tolerance and sigsegv fault checks)

        comme quoi je commente quand même un peu. Mais ce commentaire aurait sûrement pu sauter si la méthode avait été proprement découpée et ne faisait pas le café. (je suis vraiment pas fier de ce truc)

        • [^] # Re: Il y a plusieurs formes de commentaires.

          Posté par  (site web personnel) . Évalué à 1.

          roi c'est pas plutôt Retour sur Investissement ? (Return On Investment)

          oui, c'est foireux les trigrammes… ROI ya deux choix possibles, ça va encore… (je viens du monde des Telco… donc bon j'en ai bouffé, le pire c'est que tu finis par comprendre les phrases même quand le même sigle ou acronyme est utilisé dans deux contextes différents, par exemple : "les tickets MST(*) ne sont pas forcément transmis dans le cadre du roaming, c'est moins pire qu'une MST même si c'est gênant"…).

          (*) Mobile Subscriber Terminating (qui n'apparaît d'ailleurs pas sur MST…).

          • [^] # Re: Il y a plusieurs formes de commentaires.

            Posté par  . Évalué à 1.

            roi c'est pas plutôt Retour sur Investissement ? (Return On Investment)

            Dans un programme qui manipule des images, c'est moyennement crédible :) mais bon, c'est pas du code dont je suis fier… ça marche, c'est sûr, mais bon…

  • # Sélection naturelle

    Posté par  (site web personnel) . Évalué à 9.

    J'ai vu du code dans beaucoup de contextes différents (entreprise, université, logiciel libre communautaire), pas mal de langages (C++, C#, Perl, php, …), et plusieurs langues natives différentes aussi (français, anglais, japonais).

    Dans tout ça, c'est bien simple, j'y ai retrouvé partout la grande équation de l'informatique : la durée de vie d'un projet est directement liée à la qualité du code, et les commentaires en sont une composante importante. Les projets avec de mauvais commentaires meurent plus vite que les autres.

    Par contre, j'inclus le choix des noms de variables dans la qualité des commentaires. Une variable bien nommée, c'est déjà une forme de commentaire du code. Et dans certains cas c'est même suffisant (mais pas toujours).

    Bref, il n'y a même pas besoin de se battre sur la nécessité ou non des commentaires. Ceux qui ne commentent pas ne le savent peut-être pas encore… mais ils sont déjà morts.

    • [^] # Re: Sélection naturelle

      Posté par  (site web personnel, Mastodon) . Évalué à 5.

      En attendant, moi, je suis toujours obligé de bosser sur Magento… le projet n'est pas mort… :-(

      • [^] # Re: Sélection naturelle

        Posté par  (site web personnel) . Évalué à 6.

        Magento… le projet n'est pas mort… :-(

                               .+ssyss+:.                  ..     /-                    
                              +dhhhhhhhhhh+-`        `:`   mN`   yMN`                   
                             `dhhhhhhhhhhhhdhyo:     /M+   sM-  +MmMs                   
                        `:oyhdhhhs++oosyhhhhy-`      `My`-+dM/ `mN.yN.  :-   :-         
                      :shhhhhhs/---------/oydo-`      mNNMMNMs +MyohMs -M+  .M+   :+    
                    -yhhhhhhh:------------:::/---.    hMh:` md mMNdydN.hN-::hm` -dMM    
                   +dhhhhhhhy-------...----+:--:::-   sM+   mN+My`  -MdMMmdNM/ +Nshd    
                  +dhhhhhhhhd------...-s```-   `s..   /d+   sd-/.    -mN`  ym.hMs/ms    
                 `dhhhhhhhhhh+---:`    ` `.:----.-.                  .y/  /MymdyyhM+    
                 -dhhhhhhhyhhs----------/----------:                      -+/+   /M-    
                 -dhhhhhhh:/d+----------::--------::-.`                          ./-.   
                 `dhhy+ohy-:+---------------------------`                     .------:  
                  +hd:::::--:+syyhy-..:------::::::::---`                 ..-:-------`  
                   shhso+--hMMMMMMMNdmMmsym/.`.                       ..-:----.-:/-     
                   `hhhhd/:MMMMMMMMMMMMMMMN/`                    ..--:------::+:..:     
                    /hhhdy-+dNNdyyyy+o+:::--:::::  .-.`     ..--:--------------/::::    
                    `dhdhd+-----:::::---------:/:/+/o/++-------.--------::::::/:---:    
                    :dhsosoo:---------------/ss+///o/:-----------------.------/--..     
                  `.oso+++ooso///:::--:://++/+sos//o.------------------------`          
                -/////+so+o++s+////////////////sos++:.---------:--...`                  
              -/////////so+++os/////////////////s+s+o---::/-..`                         
            `////////////so+++os////////////////+s+s++oo+/+`                            
           `+////////////oo++++s/////////////////soos++//-                              
           `s+::::///+///+s++++os///////++++++++/+soo:                                  
            :---------/o/so+++++s//////////////////ooo                                  
           :----------soso++++++s+//////////////////+s.                                 
          -----------o+++++++++ooo///////////////////+/                                 
         `:.--------oo+++++++++ooo////////////////////+.                                
         --.------.+o+++++++++++oo/////////////////////+
        
        

        Désolé, c'était plus fort que moi !
        Et je compatis, pour avoir bossé un peu avec. Mais le problème de magento c'est qu'il n'y a pas que les commentaires qui soient moisis, loin de là.
        Parfois c'est même à ce demander comment ça tombe en marche. (mais par contre pas de problème pour savoir pourquoi c'est lent…)

      • [^] # Re: Sélection naturelle

        Posté par  . Évalué à 1.

        Je suis désolé. J'espère que ça ne durera pas trop longtemps.

    • [^] # Re: Sélection naturelle

      Posté par  (site web personnel) . Évalué à 10.

      Dans tout ça, c'est bien simple, j'y ai retrouvé partout la grande équation de l'informatique : la durée de vie d'un projet est directement liée à la qualité du code

      A condition que le projet aboutisse…

      Il y a quand même beaucoup de mauvais codes en prod et de nombreux beaux codes dans le cimetière des projets jamais livrés.

      Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Sélection naturelle

      Posté par  . Évalué à 1.

      mais justement, comment bien nommer une variable ?

      • [^] # Re: Sélection naturelle

        Posté par  . Évalué à 3.

        Code complete: excellente référence qui contient pleins de bon conseils pour ca et pour beaucoup d'autre choses

        • [^] # Re: Sélection naturelle

          Posté par  (site web personnel) . Évalué à 3.

          Tiens, je vois qu'on a les mêmes références :)

          Très bon bouquin, bien qu'il provienne de chez Microsoft Press diront les mauvaises langues. C'est assez complet, peut-être pas très actuel par certains côtés, mais c'est un bon bouquin. Je le conseil vraiment à tous les programmeurs.

          • [^] # Re: Sélection naturelle

            Posté par  . Évalué à 3.

            En même temps quelqu'un qui jugerait la qualité de quelqu'un par ce qu'il bosse chez MS ou d'un bouquin par ce qu'il est publié par MS est un idiot ;)

            En fait ce bouquin ou pourrait en faire un calendrier du type "un jour un conseil" sauf qu'il y a de quoi tenir 10 ans. Il est vieux mais ne s'est pas tant démodé que ca, la plupart des conseils et remarques sont intemporelles et ca fait toujours du bien de l'ouvrir au hasard.

      • [^] # Re: Sélection naturelle

        Posté par  . Évalué à 3. Dernière modification le 24 avril 2013 à 11:00.

        Déjà, ne pas utiliser d'abréviations: l'auto-complétion, s'pas pour les chiens.
        Et finalement, utiliser des noms qui veulent dire quelque chose, de préférence qui se réfère au rôle de la variable/fonction/méthode/classe.
        Cette phrase à le mérite de bannir les noms à 1 lettre, sauf cas particuliers: i, j pour les compteurs de boucle, x, y, z pour des coordonnées…

        Il m'arrive d'utiliser le mot "ret" (abréviation) parce que return est un mot-clé, cependant. Tmp aussi, même si c'est rare et limité à de très petites fonctions/méthodes, et idem j'essaie d'éviter.

        J'ai vu des conseils qui indiquent d'utiliser des noms pour les variables et objets et des verbes d'action pour les méthodes/fonctions, c'est pas trop mal, mais parfois limité quand on utilise l'anglais (print? Mais print what?) donc je dirais garder le coup du verbe d'action et le compléter si nécessaire (printPageNumber, ah, ok).

        Ensuite, je pense que le reste c'est en fonction du langage et des conventions de l'équipe:
        * si t'as pas de typage fort, la notation hollandaise n'est pas une mauvaise idée, sinon si.
        * si le langage tends à utiliser camelCase, et que l'équipe veut faire du code qui soit aisément distinguable de la lib standard, on peut vouloir utiliser les _ pour séparer les mots, par exemple.
        * si l'équipe préfère utiliser le français pour coder, l'utiliser.
        * …

        A noter: rien de tout ça ne doit être utilisé comme règle absolue :)

  • # question hors sujet

    Posté par  . Évalué à 3.

    c'est en quel langage le bout de code sur la photo ?

  • # Et les tests alors ?

    Posté par  (site web personnel) . Évalué à 5.

    Tiens, un point qui, étrangement, n'est pas arrivé ici.

    Qu'en est-t-il des tests en tant que documentation ? Est-ce que les tests (unitaires, fonctionnels) peuvent décrire l'intention ?

    Pour ma part j'ai pas un avis tranché sur ce point. Je pense que les tests aident beaucoup, mais de là à couvrir les besoins de commentaires, d'intention, je ne le pense pas. Et vous, vous en pensez quoi ?

    • [^] # Re: Et les tests alors ?

      Posté par  . Évalué à 2.

      Ah ben justement je pensais écrire un commentaire allant dans ce sens :)

      Donc moi je développe en ruby et rails, et depuis maintenant deux ans, j’utilise vraiment bien les tests sur tous mes projets (pro et perso). Pour ça j’utilise RSpec/MiniTest et Cucumber.

      Je ne suis pas un partisan à la base du commentaire à tout va, j’en écrit assez peu moi-même, je n’en mets que lorsque je juge ça utile et que le bout de code ne va pas être facilement compréhensible ou pour décrire l’intention comme il est dit plus haut.
      J’avoue que depuis que j’ai pris l’habitude d’écrire des tests et ben ça change la vie ! J’essaie (même si c’est pas évident tout le temps) de couvrir le maximum de cas possibles pour une méthode donnée.
      Avec RSpec et ses notions de context/describe, c’est facile pour décrire par bloc ce qu’il se passe quand on est dans tel cas, puis dans tel autre, etc (je connais pas trop les autres systèmes de tests hors ruby & co). Et il y a une option pour faire passer les tests en mode « documentation » justement, ce qui permet d’avoir un affichage propre et de savoir facilement que telle méthode va se comporter de telle manière dans tel cas, puis comme ça dans un autre, etc.

      Donc de mon expérience, je pense que les tests unitaires & co sont même mieux que du commentaires s’ils sont bien écrits et de manière consciencieuse puisque contrairement à un commentaire, le test est exécutable et du coup reflète la réalité et est censé être pété s’il n’est plus en phase avec le code. Bon évidemment un test tout pourri qui vérifie que true == true ne servira pas à grand chose et continuera de passer :)

    • [^] # Re: Et les tests alors ?

      Posté par  . Évalué à 3.

      Je pense qu'il faut distinguer les tests unitaires classiques type (j|cpp|php)unit et le bdd (avec cucumber par exemple). Quand tu utilise des techno comme cucumber tu t'approche de beaucoup du literate programming et tu en arrive à décrire ton code plus qu'autre chose.

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Et les tests alors ?

      Posté par  (site web personnel) . Évalué à 2.

      Qu'en est-t-il des tests en tant que documentation ?

      tu as loupé cette partie du journal :

      Quoi qu'il en soit, cette présentation s'intéresse aux "bugs" de notre cerveau et montre, comment des pratiques telles que le TDD, le pair programming, nous aident à combattre ses bugs, du type biais de confirmation, effet Dunning-Kruger, etc.

      bon, il faut savoir ce que veut dire TDD :)

      Et vous, vous en pensez quoi ?

      ne prendre en compte que les tests unitaires est àmha une hérésie ou au mieux insuffisant, ce sont les tests métiers qu'il faut prendre en compte pour avoir des commentaires pertinents ;-) (cela m'a permis de remonter aux specs dernièrement : bin oui, une exigence fonctionnelle a son test métier en face et réciproquement, pour valider les règles de gestion exprimées).

  • # Code auto-documenté

    Posté par  . Évalué à 2.

    J'ai essayé de factoriser le code pour en faire un code auto-documenté (à savoir, pas de commentaires, mais des noms de variables, fonctions, etc. qui parlent du problème).

    Je préviens tout de suite que ça va choquer les âmes sensibles, parce que j'ai fait le choix d'un code dense (Les accolades sur les ifs ? C'est pour les nuls… ;-)), et sans point virgules.

    Je ne défend pas forcément le code sans commentaires (tout comme je ne défend pas un code sans point virgule), mais je le comprend (Enfin, je comprend le principe. Quant à comprendre un code sans commentaires, ça va surtout dépendre de s'il est bien écrit).

    (function (goog) {
      /**
       * The default implementation of the import function.
       * Writes a script tag to import the script.
       *
       * @param {string} src The script source.
       * @return {boolean} True if the script was imported,
       *   false otherwise.
       * @private
       *
       */
      goog.writeScriptTag_ = function (source) {
        if (!goog.inHtmlDocument_()) return false
    
        var loadedFromBaseJs = isDependency(source)
        if (shouldNotWrite(source, loadedFromBaseJS)) return false
    
        doc.write(tag(source))
        return true
      }
    
      var doc = goog.global.document
    
      var isDependency = function (source) {
        return /\bdeps.js$/.test(source)
      }
    
      var shouldNotWrite = function (source, pageWiped) {
        if (doc.readyState != 'complete') return false
        if (!pageWiped) throw Error(errorText(source))
        return true
      }
    
      var errorText = function (source) {
        return 'Cannot write "' + source + '" after document load'
      }
    
      var tag = function (source) {
        return '<script type="text/javascript" src="' + source + '"></' + 'script>'
      }
    })(goog)
    
    

    Il y a des choses à en dire, mais je n'ai pas envie de poster un gros pâté. Je répondrais à vos remarques si vous en avez, sinon, c'est que vous n'êtes pas intéressé et que j'ai bien fait de vous épargner le pâté (qui sera meilleur en plusieurs commentaires).

    • [^] # Re: Code auto-documenté

      Posté par  (site web personnel, Mastodon) . Évalué à 3.

      (function (goog) {
        goog.writeScriptTagToImportScript_ = function (scriptSource) {
          if (!goog.inHtmlDocument_()) return false
      
          var alreadyLoaded = isAlreadyLoaded(scriptSource)
          if (shouldNotWrite(scriptSource, loadedFromBaseJS)) return false
      
          doc.write(tag(source))
          return true
        }
      
        var doc = goog.global.document
      
        var isAlreadyLoaded = function (source) {
          return /\bdeps.js$/.test(source)
        }
      
        var shouldNotWrite = function (source, pageWiped) {
          if (doc.readyState != 'complete') return false
          if (!pageWiped) throw Error(errorText(source))
          return true
        }
      
        var errorText = function (source) {
          return 'Cannot write "' + source + '" after document load'
        }
      
        var tag = function (source) {
          return '<script type="text/javascript" src="' + source + '"></' + 'script>'
        }
      })(goog)
      
      

      J'ai un peu complété. J'aurais bien aimé avoir un argument contre les personnes qui pensent qu'il est inutile de commenter, mais là je ne suis pas convaincu. Si le commentaire ne fait que répéter le nom de la fonction alors ça ne sert à rien à part prendre de la place. Par exemple le commentaire de src : the script source devient scriptSource. On ne perd pas l'information.

    • [^] # Re: Code auto-documenté

      Posté par  (site web personnel) . Évalué à 5.

      Pas mal de choses à dire en fait, mais j'aime beaucoup la tournure que ça prend :)

      Déjà, j'aime pas tellement ni le côté "dense" sans accolades, ni l'absence de point virgule. (ni le passage du goog en fait)

      Ça, c'est fait :)

      Ensuite, honnêtement, je trouve ça plus lourd. Et surtout, il manque réellement des commentaires.
      En fait, en lisant ton code, on ne sait toujours pas pourquoi on teste l'état du document, pourquoi un lance une erreur mais pas dans le cas de deps.js.

      Donc en fait, ton code factorisé de la sorte n'amène pas de réponses, il serait même à mon avis plus compliqué de décrire les cas (car tu as changé l'ordre des conditions, même si ça ne change pas le résultat).

      Et au final je trouve ça moins lisible car cela oblige à faire des allez retour.

      Finalement j'aime bien cet exemple car c'est justement un vrai cas où ce qui est intéressant est le pourquoi et non le comment (le comment est très simple, le pourquoi beaucoup plus tordu).

      • [^] # Re: Code auto-documenté

        Posté par  . Évalué à 2.

        Je vais répondre en deux commentaires, sur deux points différents. Pour commencer, je vais parler du style.

        Au niveau du code dense et de l'absence de points virgules, c'est juste une question de style. Que je ne défendrais absolument pas !

        J'aime bien, mais je ne pense pas être capable d'imposer un tel choix (si peu orthodoxe, qui plus est) dans le cadre d'une collaboration. Il vaut mieux un code lisible par le plus grand monde. Si tout le monde dans le projet est d'accord pour ce style (ou si je veux développer en autiste et filtrer sévèrement les contributions pour les limiter aux personnes pas trop bornée :-°), un style de ce genre est ok, mais la plupart du temps on préfèrera un style éprouvé.

        La raison pour laquelle j'ai utilisé ce style est surtout parce qu'il est permit par la factorisation (ça vient tout seul). Sans la factorisation, difficile d'omettre les accolades, et si on les met à un endroit, autant les mettre partout (c'est plus consistant).

        Pour le passage du goog, on touche à la première remarque que je me suis abstenu de faire pour éviter un pâté :

        le passage de tout ce code en closure vient du fait que ce morceau de code est écrit dans un style particulier, que je n'ai pas le contexte autour, et que le style du code en question est bien différent du reste de la librairie. La closure est là pour ne pas polluer l'espace de nom (ni le global, ni le goog), mais dans un projet qui a adopté ce style de manière officielle, l'espace de noms sera adapté de manière à éviter une closure de ce genre (les fonctions sont prisonnières de ce contexte, alors qu'une partie d'entre elles peuvent être, à condition d'un nommage moins ambigüe, partagée par tout le projet).

        Éviter la closure est une remarque pertinente et importante : quand on parle de l'impact de la factorization sur les performances, on pense au coût des appels de fonctions, mais la gestion des closures est très coûteuse au niveau temps, par rapport à, par exemple, un objet javascript. (source : un benchmark que j'ai la flemme de chercher :-°). Un projet qui est pensé avec un code de ce style va donc éviter les closures (dans le cas de ce morceau de code, ça demande de renommer errorText en cantWriteError, par exemple, ou quel que soit le nouveau nom trouvé, tant qu'il est moins vague que errorText qui n'est acceptable que dans la portée locale de ce code).

        Une chose qui pour moi est importante, plus importante que la quantité de commentaires, est la cohérence du projet. Un projet peut avoir des fonctions qui font en moyenne vingt lignes avec quelque commentaires, ou une cinquantaine/centaine de lignes très commentées, ou cinq lignes sans commentaires. Dans tout les cas (pour moi), un bon codeur va écrire un code lisible dans chacun de ces styles (enfin, s'il est bon dans ce style en question). Et un mauvais codeur va écrire un code illisible, quelque soit les précautions qu'on lui a demandé de prendre. L'important est que quand on travaille sur un projet, une fois qu'on s'est fait au style, on n'a pas à en réapprendre un autre totalement différent.

        Le style que j'ai utilisé est très exigeant : les fonctions ne doivent pas faire plus de cinq lignes (j'ai pas compté, je juge à l'œil), ne pas dépasser la soixante dixième colonne de mon éditeur (en fait, une des lignes fait un peu plus, là, mais comme c'est un exemple…), et dans la mesure du possible, éviter d'avoir plusieurs expressions après un if. Si on est habitué à lire un code de ce genre, un code mal écrit devient très vite évident : fonctions trop longues, niveau d'indentation qui s'accumule… La seule incartade permise par ce style est un choix ridicule de noms. Et quand je code comme ça, je relis sans cesse mon code en me demandant : « est-ce que ce nom est vraiment pertinent ? ».

        Ça ne veut pas dire que ce style est bon pour autant. Il me force à réfléchir énormément à ce que j'écris et à son sens, et quand j'écris comme ça, je corrige souvent plein d'erreurs. Mais c'est aussi un style qui peut s'apparenter à du code spaghetti (comme tu le dis : « Je trouve ça moins lisible car cela oblige à faire des allez retour. »), et qui peut avoir un coût à force de créer des fonctions ou des variables (À supposer que ce coût ne soit pas acceptable. Ça dépend de la fréquence d'appel du code, de sa complexité, et de l'environnement d'exécution.).

        L'effet spaghetti est censé se retrouver mitigé par le fait que quand on est dans une fonction, on ne devrait pas avoir à aller voir ce que fait une autre fonction pour s'assurer que cette fonction fait bien ce qu'elle dit (donc, pas d'aller-retour). Ça, c'est dans le meilleur des mondes. C'est le résultat recherché. Mais le meilleur juge est le novice qui doit se plonger dans un code qu'il ne maîtrise pas.

        Un ami m'a affirmé préférer mon style pour la découverte d'un code (il avait deux morceaux de code équivalents pour juger), car il avait sous les yeux la « preuve » (à condition de faire confiance aux noms) que la fonction fait bien ce qu'elle dit faire.

        your mileage may vary

        La chose la plus importante pour moi reste d'avoir un seul style dans le projet : je ne proposerais jamais ce code comme patch à Google, parce que s'il est le seul de ce style dans le projet, tout le monde va faire des efforts pour le lire – même moi, peut-être, si je lis en même temps énormément de code du même projet, écrit dans le style commenté de ce journal.

        • [^] # Re: Code auto-documenté

          Posté par  (site web personnel) . Évalué à 5.

          Bon, pas mal de choses à dire :)

          Autant les ; en javascript sont discutables (rien que par leur côté simplement optionnel). Pourtant je les conserve pour deux raisons essentiellement, une bonne et une mauvaise.

          • la bonne : on ne peux pas, toujours, les supprimer. Et on se retrouve avec des horreurs genre ;!function() {… Et ça franchement, c'est dégueulasse je trouve.
          • la mauvaise : ça date du temps où on utilisait des minifieurs un peu trop bêtes : il ne faisaient que supprimer les commentaires et les espaces. Si une accolade manquait, si un point virgule manquait, c'était alors vraiment galère.

          Par contre, je suis en général contre l'inline (les block sur la ligne de la condition) et contre l'absence des accolades. Mais ça c'est pour des raisons beaucoup plus terre à terre.

          Déjà, c'est tout con, mais placer un point d'arrêt dans le bloc d'une condition c'est quand même parfois vachement pratique lorsqu'on debug. Et quand on a

          if (shouldNotWrite(scriptSource, loadedFromBaseJS)) return false
          
          

          Ben c'est juste pas possible comme ça :)

          Le deuxième point c'est que, parfois, on va vouloir ajouter une ligne de log (par exemple). Et si on va un peu trop vite, en plein debug, on va avoir des choses sympa.

          Genre

          if (shouldNotWrite(scriptSource, loadedFromBaseJS))
            return false
          
          

          va se transformer en

          if (shouldNotWrite(scriptSource, loadedFromBaseJS))
            console.log('shouldNotWrite')
            return false
          
          

          Et là, c'est le drame.

          Ensuite, il y a simplement des cas où on ne peut pas s'en passer (plus d'une instruction) et on arrive parfois à :

          if (shouldNotWrite(scriptSource, loadedFromBaseJS)) {
            console.log("shouldNotWrite")
            return false
          } else
            console.log("shouldWrite")
          
          

          Et là, franchement, c'est gerbant.

          Et enfin, dernier cas, en obligeant les accolades et interdisant plusieurs instructions sur la même ligne, je vais éviter que quelqu'un me sorte un truc de ce genre :

          using namespace std;
          
          vector<int> myIntVector;
          vector<int>::iterator myIntVectorIterator;
          
          // Add some elements to myIntVector
          myIntVector.push_back(1);
          myIntVector.push_back(2);
          myIntVector.push_back(3);
          myIntVector.push_back(4);
          myIntVector.push_back(5);
          
          for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) if (*myIntVectorIterator % 2) {
              cout<<*myIntVectorIterator<<" ";
              //Should output 1 3 5
          }
          
          

          (cet exemple est beaucoup plus sympa si vous n'avez pas de retour automatique à la ligne ;-) )

          Et là, vraiment, je peux plus le voir ce type de code.

          Alors c'est peut-être pas totalement fun mes diverses règles, mais pour le coup c'est réellement l'expérience qui parle. Ce que je veux dire c'est que tous ces cas je les ai rencontré en vrai, certains bien plus qu'une fois.
          Et les conventions de code, si elles doivent permettre d'avoir un code élégant, doivent aussi s'assurer que tout fonctionnera au mieux, en prenant si possible en compte les erreurs humaines.

          Après, sur le côté closure. Par exemple, le doc = goog.global.document est assez particulier, surtout que je n'en vois pas du tout l'intérêt. En plus, il est utilisé avant sa déclaration (ok, c'est pas forcément un problème, mais quand même).

          De manière globale, je trouve qu'il faut plus d'effort pour lire ton code que la version initiale. Ok, chaque méthode est plus petite. Mais finalement c'est tellement morcelé que ça complexifie la lecture et la compréhension, alors que quand même, le code initial est plutôt simple :)

          Avoir des limites genre pas plus de 5 lignes, j'en vois pas vraiment l'intérêt. A part mettre chaque instruction ou condition dans une méthode qui lui est propre, mais ça revient à découper pour découper là. D'ailleurs je trouve étrange de limiter la taille des lignes et en même temps vouloir tout mettre sur une ligne…
          Par exemple, lorsque tu lis la méthode principale, tu n'as absolument aucune idée du fait que ça peut lever une erreur. Pour le savoir, il faut que tu fouilles dans les fonctions. D'ailleurs ta fonction, shouldNotWrite, n'est pas explicite. On ne s'attend pas à ce que ça lève une erreur non plus.

          Idem, le côté not / false, c'est pas génial en général. A la rigueur si on avait du unless ça serait différent par exemple.

          • [^] # Re: Code auto-documenté

            Posté par  . Évalué à 2.

            De manière globale, je trouve qu'il faut plus d'effort pour lire ton code que la version initiale. Ok, chaque méthode est plus petite. Mais finalement c'est tellement morcelé que ça complexifie la lecture et la compréhension, alors que quand même, le code initial est plutôt simple :)

            Je me suis dis la même chose, mais je pense que c'est parce que je ne suis pas habitué à ce style d'écriture.
            Je pense que ça aurait été plus lisible si les définitions des fonctions n'étaient pas imbriquées. J'ai toujours trouvé absolument vomitif ce type de choses, et pour moi, même si les lambdas sont parfois utiles, je trouve qu'en abuser n'est pas vraiment une bonne chose.

            En fait, je suis d'accord avec ton intervention, mais je pense que ce qui rend le code difficile a lire, au moins dans mon cas, est que j'ai plusieurs handicap:
            * je maîtrise pas JS,
            * j'aime les langages typés (pour moi, savoir qu'une variable est un entier, signé ou pas, par exemple, aide à comprendre son futur rôle: non signé? Ah, peut-être un index… signé? Probablement pas.),
            * je supporte difficilement les lignes avec plusieurs instructions (sauf cas très précis, et jamais sur de boucles/conditions)

            Mais toutes ces raisons qui font que je lis mal son code n'ont rien à voir avec la présence ou pas de commentaires.

            PS: vive le C++11 pour le range loop, auto, et les lambda :p

            • [^] # Re: Code auto-documenté

              Posté par  . Évalué à 1.

              Je pense que ça aurait été plus lisible si les définitions des fonctions n'étaient pas imbriquées.

              Mais les définitions des fonctions ne sont pas imbriquées, là…? Et la closure au début définit juste un espace de nom.

              Personnellement, je n'aime pas non plus quand c'est imbriqué. Une de mes règles arbitraire est « pas plus de trois indentations » (de toute façon, si on limite la taille des lignes, les indentations sont très vite un problème).

              je supporte difficilement les lignes avec plusieurs instructions (sauf cas très précis, et jamais sur de boucles/conditions)

              Ce genre de pratiques a dû causer au moins autant de traumatismes que le goto ;-)

              j'aurais peut-être dû me contenter de factoriser, et adopter un style plus courant… Là, le débat se déplace sur d'autres horizons. (ça m'apprendra à faire le malin :-°)

          • [^] # Re: Code auto-documenté

            Posté par  (site web personnel) . Évalué à 5.

            Je complète juste un des exemples (tiré d'un vrai code hein…)

            using namespace std;
            
            vector<int> myIntVector;
            vector<int>::iterator myIntVectorIterator;
            
            // Add some elements to myIntVector
            myIntVector.push_back(1);
            myIntVector.push_back(2);
            myIntVector.push_back(3);
            myIntVector.push_back(4);
            myIntVector.push_back(5);
            
            for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) if (*myIntVectorIterator % 2) {
                cout<<*myIntVectorIterator<<" ";
                //Should output 1 3 5
            
                // bla bla bla
            
                // bla bla
            } else {
                // bla bla
            }
            
            

            Oui, en général quand tu vois ça il y a subitement pas mal de supplices qui te viennes à l'esprit ;-)

          • [^] # Re: Code auto-documenté

            Posté par  . Évalué à 1.

            if (shouldNotWrite(scriptSource, loadedFromBaseJS))
              return false
            
            

            Ça, de toute façon, c'est interdit. Pour la raison que tu cites. S'il y a retour à la ligne, il faut les accolades. Dans le même genre, si il y a des accolades sur le if, on en met sur le else. En général, je vote pour une règle stricte : pas d'accolade du tout (et donc conditions sur une ligne), ou toujours des accolades (et quand je dis toujours, ça veut dire même quand ça pourrait tenir sur une ligne). Et comme je l'ai dit, à moins que tout le monde soit d'accord avec ce style très particulier, j'irai sur plus traditionnel (accolades, point virgules…).

            Après, sur le côté closure. Par exemple, le doc = goog.global.document est assez particulier, surtout que je n'en vois pas du tout l'intérêt. En plus, il est utilisé avant sa déclaration (ok, c'est pas forcément un problème, mais quand même).

            J'ai gardé cette partie du code d'origine, parce que j'avais déjà la closure (pour pas polluer la bibliothèque autour). Je l'ai placé après (comme le reste des définitions) pour rester cohérent avec le commentaire. À la base, j'avais :

            /* --- (function (goog) { */
            /**
             * The default implementation of the import function.
             * Writes a script tag to import the script.
             *
             * @param {string} src The script source.
             * @return {boolean} True if the script was imported,
             *   false otherwise.
             * @private
             *
             */
            /* +++ */ (function (goog) {
              goog.writeScriptTag_ = function (source) {
                if (!goog.inHtmlDocument_()) return false
            
                var loadedFromBaseJs = isDependency(source)
                if (shouldNotWrite(source, loadedFromBaseJS)) return false
            
                doc.write(tag(source))
                return true
            
            

            J'aurais peut-être pu remettre le code dans l'ordre « traditionnel » après avoir passé la closure au dessus du commentaire… Il ne faut pas s'arrêter sur la closure qui est ici un détail.

            Avoir des limites genre pas plus de 5 lignes, j'en vois pas vraiment l'intérêt. A part mettre chaque instruction ou condition dans une méthode qui lui est propre, mais ça revient à découper pour découper là. D'ailleurs je trouve étrange de limiter la taille des lignes et en même temps vouloir tout mettre sur une ligne…

            Les fonctions de cinq lignes, ce n'est pas une règle absolue (comme j'ai dit, je fais à vue d'œil), c'est juste que quand chaque action a un nom qui indique le but de l'action, on se retrouve avec des fonctions aussi courtes. La limite sur la taille de la ligne, elle, par contre, est une vrai limite. Elle est couplée à une autre limite : ne pas utiliser d'abréviations. Enfin, mise en parallèle avec le choix fait ici de ne pas utiliser d'accolades (donc, boucles, ifs, etc. sur une seule ligne), ça oblige vraiment à réfléchir. Oui, on découpe pour découper, mais au passage, on réfléchit au but du morceau de code qu'on est en train de découper. On doit lui chercher un nom, significatif, court…

            Certains langages s'y prêtent mieux que d'autre. Dans un langage objet, le résultat est souvent qu'on se rend compte qu'une partie de notre logique devrait être placée dans une nouvelle classe. En Forth, les fonctions peuvent tenir sur une ligne parce que le passage d'arguments est implicite, et elles doivent tenir sur une ligne parce que sinon on n'arrive plus à suivre l'état de la pile. Dans un langage comme le C, c'est plus difficile, parce qu'on doit passer tout les paramètres, on ne peut pas avoir plusieurs fonctions du même nom (en orienté objet, on peut tant que la méthode appartient à un objet différent)…

            Pour reprendre ton exemple :

            for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) if (*myIntVectorIterator % 2) {
                cout<<*myIntVectorIterator<<" ";
                //Should output 1 3 5
            }
            
            

            Ce code ne passe pas selon mes règles. C'est un exemple, très abstrait, je ne peux donc pas proposer de solution, mais face à un code de ce genre, je réfléchis énormément pour raccourcir la ligne de 144 caractères. Je suppose que je mettrais justement le if/else dans une autre fonction, avec un nom qui indique ce que fait cette condition. myIntVectorIterator est un nom très long, est-ce qu'il n'y en a pas un plus court qui ait un sens dans le contexte actuel ?…

            Le but de cette règle est de forcer le développeur à penser jusqu'au bout à ce qu'il est en train de faire. Si un mauvais développeur vient toucher au code, on le verra tout de suite parce qu'il sera incapable de suivre les règles (ici, mauvais est très subjectif, peut-être que je suis un mauvais développeur, après tout ;-)). Ce qui rejoint ceci :

            Et les conventions de code, si elles doivent permettre d'avoir un code élégant, doivent aussi s'assurer que tout fonctionnera au mieux, en prenant si possible en compte les erreurs humaines.

            En ce sens je suis totalement d'accord avec toi. Et mes règles ne sont pas fun non plus ;-). Les tiennes sont sûrement plus éprouvées, par contre, parce qu'elles sont suivies par la majorité de l'industrie. Mis à part dans mes propres projets, et dans quelque codes en Forth, je n'ai jamais rencontré un style aux choix aussi radicaux que le mien. Ah si, en smalltalk aussi (les méthodes sont souvent très courtes).

            À noter qu'en smalltalk, il y a deux types de commentaires : les commentaires inline (assez rare), et les commentaires de la classe/de la méthode, présentés à part. Ceux-ci sont courants, et sont censés être précis.

            Le code que j'ai présenté ne contient aucun commentaire, parce que c'est le sujet du journal. Si le sujet du journal avait été l'inutilité d'un code très découpé, j'aurais sûrement fait comme en smalltalk : indiqué ce que fait chaque fonction, pourquoi elle existe… Mais il n'y aurait pas eu plus de commentaire inline.

            Je distingue la documentation et le commentaire. Un commentaire n'a pas de sens sans le code qu'il accompagne. La documentation en a. Aussi, je distingue deux types de documentation : la documentation interne au module, et la documentation externe. La documentation externe est accompagnée du prototype des fonctions, d'exemple sur comment les utiliser, etc. La documentation interne décrit le contexte d'exécution, les pièges à éviter… Mais dans les deux cas, il devrait être possible de présenter cette documentation de manière bien distincte du code (comme en smalltalk, la documentation et le code sont dans un onglet différent). Une fois le contexte connu, le code devrait pouvoir être lu sans avoir à être annoté. L'intérêt pour moi d'avoir une documentation à part est qu'elle peut être mieux rédigée, couvrir une plus grande portion de code, offrir une vue d'ensemble de ce qu'on cherche à faire… Alors qu'un commentaire est très localisé. Par contre, cela demande un travail supplémentaire (tout comme la factorisation à outrance demande un travail de réflexion et de nommage supplémentaire).

            Après, quand je parle de documentation à part, je n'érige pas ça comme une règle : l'idée de la javadoc, à savoir, la documentation de la fonction à côté de la fonction, est pertinente à mon avis, puisqu'elle permet de vérifier plus rapidement la validité du code, synchroniser la documentation aux code… De la même manière, on peut envisager de mettre la documentation interne avec le code. Mais le commentaire traditionnel n'est pour moi pas la place de cette documentation. Au début du fichier, pour comprendre à quoi on touche avant même de plonger dans le code, est la place appropriée pour cette documentation. Ou bien, comme en programmation lettrée, avec le code – mais le code est alors une illustration de la documentation. Quoi qu'il en soit, on ne commente pas le code, on documente notre problème. Le code reste une information à part et auto-suffisante quand le problème est maîtrisé.

            Mais je suppose que, d'une certaine manière, je t'accorde là un point, puisqu'au final, il y a une documentation. Le débat porte juste sur la place de celle-ci, et la lisibilité du code selon la place occupée par la documentation.

            (Je suis rentré dans le débat pour montrer un exemple de code sans commentaire en essayant de garder le sens de ceux-ci, comme un défi. Après, je parle de mes goûts, mais comme vous pouvez le voir, mes goûts ne bannissent pas les commentaires, ils les déplacent… ;-))

            • [^] # Re: Code auto-documenté

              Posté par  (site web personnel) . Évalué à 2.

              Je répond en deux fois, une fois rapide sur quelques points et je ferai plus long plus tard (taff, toussa)

              Pour reprendre ton exemple :

              for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) if (*myIntVectorIterator % 2) {
                 cout<<*myIntVectorIterator<<" ";
                 //Should output 1 3 5
              }
              

              Ce code ne passe pas selon mes règles. C'est un exemple, très abstrait, je ne peux donc pas proposer de solution, mais face à un code de ce genre, je réfléchis énormément pour raccourcir la ligne de 144 caractères. Je suppose que je mettrais justement le if/else dans une autre fonction, avec un nom qui indique ce que fait cette condition. myIntVectorIterator est un nom très long, est-ce qu'il n'y en a pas un plus court qui ait un sens dans le contexte actuel ?…

              En fait le premier problème de ce code est justement le fait d'aller à la ligne (le if sur la ligne du for)

              Ensuite, pour le rendre par certains côtés plus lisible, il faut "juste" comprendre ce qu'est un for :

              vector<int>::iterator myIntVectorIterator = myIntVecor.begin();
              while(myIntVectorIterator != myIntVector.end()) {
                // bla bla
                myIntVectorIterator++;
              }
              
              

              Et d'ailleurs il devient plus aisé de remplacer le corps du for par une méthode. L'inconvénient (enfin si le corps du for est trop long) est qu'on voit moins vite l'itération, même si on s'en doute fortement.

              Pour l'histoire des accolades : arrive-t-on réellement a un code où il n'y a jamais deux instructions dans un if/else/autre ? Si oui, alors il peut être envisageable de se passer d'accolades. Mais ça + une largeur de ligne faible, ça me semble étrange. Mais peut-être est-ce possible, auquel cas c'est intéressant ;)

              (la suite un peu plus tard)

              • [^] # Re: Code auto-documenté

                Posté par  . Évalué à 4.

                vector<int>::iterator myIntVectorIterator = myIntVecor.begin();
                while(myIntVectorIterator != myIntVector.end()) {
                  // bla bla
                  myIntVectorIterator++;
                }
                

                Et d'ailleurs il devient plus aisé de remplacer le corps du for par une méthode. L'inconvénient (enfin si le corps du for est trop long) est qu'on voit moins vite l'itération, même si on s'en doute fortement.

                Je préfère personnellement la boucle for quitte à la mettre sur 3 lignes (je ne touche pas aux noms, ni n'ajoute de typedef, mais je le fais presque systématiquement) :

                for(vector<int>::iterator myIntVectorIterator = myIntVector.begin();
                    myIntVectorIterator != myIntVector.end();
                    myIntVectorIterator++) {
                  // bla bla
                }
                
                

                L'avantage c'est qu'on voit qu'il s'agit d'une itération complète. On sait qu'il s'agit d'un foreach, ça ne laisse pas de place à l'imagination.

                Après faut être un peu réaliste et plutôt utiliser les outils standards qui sont à disposition :

                for_each( myIntVector.cbegin(), myIntVector.cend(), bla_bla);
                
                

                ou

                for (int &myIntVectorIterator : myIntVector) {
                    // bla bla
                }
                
                

                On gagne énormément sans toucher aux identifiants. C'est quand l'itération n'est pas complète que la question peut se poser. Comme ça par exemple :

                auto myIntVectorIterator = myIntVector.begin();
                while(myIntVectorIterator != myIntVector.end()
                      && *myIntVectorIterator < N) {
                    // bla bla
                    ++myIntVectorIterator;
                }
                
                

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

              • [^] # Re: Code auto-documenté

                Posté par  . Évalué à 2.

                Pour l'histoire des accolades : arrive-t-on réellement a un code où il n'y a jamais deux instructions dans un if/else/autre ? Si oui, alors il peut être envisageable de se passer d'accolades. Mais ça + une largeur de ligne faible, ça me semble étrange. Mais peut-être est-ce possible, auquel cas c'est intéressant ;)

                C'est un exercice que je trouve intéressant. Je n'ai pas encore rencontré de cas où c'était impossible, mais je n'ai pas non plus souvent codé des trucs extrêmement complexes.

                Il y a des langages où c'est beaucoup plus facile. En premier, Forth, puisque c'est de là que j'ai tiré cette pratique. Ensuite, les langages objets, parce qu'on peut passer l'information de manière peu verbeuse (le contexte de l'objet est partagé entre les méthodes, pas besoin de passer cinquante arguments). Dans un langage comme le C, ça devient plus compliqué de faire tenir le code sur une seule ligne.

                Pour tenir sur des lignes courtes, il faut des noms courts. C'est facile en Forth ou on peut redéfinir un mot sans affecter le comportement des fonctions précédemment définies. C'est possible avec les langages objets, parce qu'il est possible de trouver des noms courts quand le projet est bien structuré : une variable est un nom, une méthode est un verbe, et effectuer une action consiste à écrire une phrase. Et on peut toujours découper un texte en phrases courtes. Mais là encore, c'est possible parce qu'un même mot peut avoir différentes significations (suivant le contexte, ici, l'objet dans lequel on travaille). Ceci-dit, un nom idéal est un nom composé d'un seul mot. J'atteins rarement ce stade avec les langages objets, comme on peut le voir dans le code que j'ai présenté. Mais la limite de taille m'oblige à me triturer suffisamment les méninges pour éviter le traditionnel piège du « FactoryOfSingletonFactoryOfUserComment ».

                • [^] # Re: Code auto-documenté

                  Posté par  (site web personnel) . Évalué à 1.

                  Il y a des langages où c'est beaucoup plus facile. En premier, Forth, puisque c'est de là que j'ai tiré cette pratique.

                  ah, du Forth, un langage que j'avais bien aimé. Malheureusement, jamais retrouvé en entreprise :/ Connaîtrais-tu quelques exemples ?

                  • [^] # Re: Code auto-documenté

                    Posté par  . Évalué à 3.

                    Mis à part Forth Inc. et Green Arrays (où travaille maintenant Chuck Moore) ? Non, je n'ai pas d'autre exemples d'entreprises qui utilisent actuellement et ouvertement Forth. Les entreprises/organisation connues pour avoir utilisé Forth ne font pas que ça (il y avait les BIOS de Sun, des projets à la Nasa…), et en font très peu.

                    Si vous ne connaissez pas Green Arrays et que vous êtes curieux, je vous invite à aller voir, ça vaut le coup d'œil : ils poussent le concept du processeur multi-core plus loin en créant des puces contenant 144 ordinateurs. Chaque ordinateur a sa propre mémoire, utilise très peu d'énergie, se met en veille/sort de veille automatiquement, est très rapide… Chaque ordinateur est bien sûr limité (très peu de mémoire, jeux d'instruction minimaliste), mais peut communiquer avec les autres ordinateurs de la puce.

                    Bien sûr, ça donne un résultat différent de ce dont on a l'habitude. C'est souvent le cas dans l'univers de Forth, je trouve : c'est différent, mais ça reste de l'informatique, et ça fonctionne. Et dans mon cas, ça me fascine ^_^

                    (mmmh… mais on n'est plus du tout dans le sujet du journal :-°)

                    • [^] # Re: Code auto-documenté

                      Posté par  (site web personnel) . Évalué à 1.

                      (mmmh… mais on n'est plus du tout dans le sujet du journal :-°)

                      non, là on est dans les commentaires du nourjal :-) (et tout est possible sur LinuxFr.org).

                      hmmm Green Arrays leur business model c'est vendre des chips et le logiciel ? Ils n'y gagneraient pas à mettre le logiciel en libre, fournir les émulateurs et vendre plus de chips ainsi ? (avec les contrats de support, l'expertise toussa pour fournir du logiciel exploitant au mieux les chips…).

                      • [^] # Re: Code auto-documenté

                        Posté par  . Évalué à 3.

                        Le logiciel est gratuit. On peut le trouver ici. Il n'est pas libre, par contre : on a le droit de faire pas mal de choses avec, mais pas n'importe quoi – pas d'utiliser leur code pour leur faire de la concurrence – et la licence du polyForth fournit vient de Forth inc. avec encore moins de droits.

                        Leur business model, c'est donc de vendre les puces, pas le logiciel. Par contre, dans l'entreprise, ils codent en Forth.¹ On peut aussi s'attendre à ce que leurs clients codent en Forth (l'architecture est tellement exotique qu'essayer de créer un compilateur C pour la bête n'est pas des plus pertinents…).

                        Mais je ne connais pas leurs clients ;-).

                        ¹ : Tu demandais des exemples d'entreprises qui codent en Forth. Bon, c'est pas des exemples très pertinents, mais c'est les seuls que je connais.

            • [^] # Re: Code auto-documenté

              Posté par  . Évalué à 1.

              Je suppose que je mettrais justement le if/else dans une autre fonction, avec un nom qui indique ce que fait cette condition. myIntVectorIterator est un nom très long, est-ce qu'il n'y en a pas un plus court qui ait un sens dans le contexte actuel ?…

              D'un autre côté, si tu as une boucle sur un ensemble de données appartenant à un conteneur (allez, un vector, soyons fous) ou tu n'effectue une action que dans un cas, il y a les algo du C++ (et j'oublie volontairement pour le moment le C++11 qui a introduit range_loop et lambda):

              • for_each
              • transform
              • find_if

              Sachant que le reproche le plus populaire fait au C++ est la petite taille et le manque de fonctionnalités de la lib standard, j'imagine que les autres langages n'ont pas cette lacune?

              for(myIntVectorIterator = myIntVector.begin(); myIntVectorIterator != myIntVector.end(); myIntVectorIterator++) if (*myIntVectorIterator % 2) {
                  cout<<*myIntVectorIterator<<" ";
                  //Should output 1 3 5
              }
              
              
              void print(int i)
              {
                if(i%2)
                  std::cout<<i<<" ";
              }
              ...
              ...
              ...
                for_each(myIntVector.begin();myIntVector.end();print);
              
              

              Je sais que cette ancienne méthode n'était pas appréciée (code déporté ailleurs, et syntaxe pénible quand on veut plus d'arguments due à l'emploi de foncteurs, entres autres) mais je trouve que ça réduit l'illisibilité de certaines (plus de la moitié des boucles for je pense) boucles de façon assez propre.
              Pas les boucles for ou l'on incrémente plus d'un pointeur (toujours trouvé ça dégueu perso), ni les boucles où l'intervalle n'est pas connu avant l'exécution du corps, ni celle ou le pas n'est pas uniforme, par contre.
              Donc, dès qu'on utilise un truc genre "exit" ou "return" au milieu de la boucle, des modifications du compteur/itérateur, ça n'aide plus.

              Maintenant, si je prend Java, ou un C++ plus moderne (allez, va pour C++, moins de risque de me lourder):

              for(auto i: myIntVector)
              {
                if(i%2)
                  std::cout<<i<<" "; 
              }
              
              

              Je pense qu'il n'y a nul besoin de commenter de tels codes (pourtant j'ai même viré le type de i, chose que je ne fais pas trop)…

              (oui, je sais que je vais dans ton sens, mais pour moi on peut très bien se passer de commentaires explicites et avoir un code documenté. Même si parfois les commentaires aident.)

      • [^] # Re: Code auto-documenté

        Posté par  . Évalué à 2.

        Deuxième partie de ma réponse, en réaction à ce point :

        Ensuite, honnêtement, je trouve ça plus lourd. Et surtout, il manque réellement des commentaires.
        En fait, en lisant ton code, on ne sait toujours pas pourquoi on teste l'état du document, pourquoi un lance une erreur mais pas dans le cas de deps.js.

        J'ai justement essayé de ne pas perdre le contenu des commentaires, ce qui m'a demandé un peu d'imagination. Mais, c'est vrai, le contenu est maintenant dilué et parfois implicite.

        // If the user tries to require a new symbol after document
        // load, something has gone terribly wrong. Doing a
        // document.write would wipe out the page.
        
        

        Pour ce premier commentaire, c'est vrai qu'on ne précise plus qu'écrire un commentaire pourrait effacer la page. On précise juste qu'il y a des cas où l'on ne devrait pas écrire :

        if (shouldNotWrite(source, loadedFromBaseJS)) return false
        
        

        Si on lit shouldNotWrite, on sait pourquoi on ne devrait pas écrire :

        if (doc.readyState != 'complete') return false
        
        

        Bon, là, on atteint une double négation (… faut que je réfléchisse à un meilleur nom, donc ;-)), mais une fois ce problème logique surmonté, on comprend que la condition pour écrire est que le document n'aie pas finit d'être chargé. Est-il nécessaire de préciser pourquoi il ne faut pas écrire dans un document déjà « scellé » ? (je viens d'y penser, je pourrais englober le test dans une fonction au nom plus évocateur, justement : documentSealed())

        Le contenu du second commentaire est, lui, plus implicite.

        // Certain test frameworks load base.js multiple times,
        // which tries to write deps.js each time. If that happens,
        // just fail silently. These frameworks wipe the page
        // between each load of base.js, so this is OK.
        
        

        Donc, on échoue silencieusement si la page a déjà été effacée ? Sinon, on déclenche une erreur ? Et pourquoi la page aurait déjà été effacée ? Parce que « base.js » a déjà été chargé ?

        Tout les éléments sont dans le code, mais éparpillés et implicites :

        Si notre code est une dépendance, dans ce contexte précis, il a été appelé par « base.js » (Ou bien il y a une erreur dans le code ? Je me fie au code et aux commentaires pour faire cette assomption.).

        var loadedFromBaseJs = isDependency(source)
        
        

        À quoi sert loadedFromBaseJS ? Et bien il est passé comme paramètre pageWiped. Donc, si le code est une dépendance, il a été chargé à partir de « base.js », et cette information est importante pour nous pour savoir si la page a été effacée.

        Pourquoi veut on savoir si la page a été effacée ?

        if (!pageWiped) throw Error(errorText(source))
        
        

        D'accord. Si la page n'a pas été effacée, on n'a pas affaire a une opération anodine. Rien que d'avoir essayé est mauvais, on plante.

        Tout les éléments sont donc dans le code. Plus que le comment, le pourquoi est là aussi. Seulement, il faut inférer le pourquoi. Le commentaire a l'avantage de prémacher le travail. Il a aussi l'inconvénient, parfois, de mettre notre cerveau sur off, ce qui peut s'avérer gênant si le commentaire et le code ne sont pas synchronisés.

        Bonus : mise à jour de la partie impliquant shouldNotWrite :

        goog.writeScriptTag_ = function (source) {
          if (!goog.inHtmlDocument_()) return false
        
          var loadedFromBaseJs = isDependency(source)
          if (!writePossible(source, loadedFromBaseJS)) return false
        
          doc.write(tag(source))
          return true
        }
        
        var writePossible = function (source, pageWiped) {
          if (!documentSealed()) return true
          if (!pageWiped) throw Error(errorText(source))
          return false
        }
        
        var documentSealed = function () {
          return doc.readyState == 'complete';
        }
        
        

        Maintenant, j'avais même commencé à mettre des bout de code « inutiles », juste « sémantiques » quand j'ai commencé à refactoriser. Un truc du genre :

        pageWiped = loadedFromBaseJS = isDependency(source)
        
        

        Là, l'idée n'est plus de virer les commentaires, mais bien de ne parler qu'un seul langage : javascript.

        Quand on dit qu'un code bien écrit se passe de commentaires, c'est un peu comme dire qu'un texte bien écrit en anglais peut se passer de commentaires en français. On veut ne parler qu'un seul langage, et y placer toute l'information dont on dispose. Un commentaire en javascript, « it's an english citation in a french text ».

        Après, j'essaye de montrer des exemples, je défend le point de vue des « sans commentaire », mais je suis un extrémiste : cela se voit dans les règles que je me suis fixé pour le style (voir mon commentaire précédent). Je suis juste un extrémiste dans les deux sens : je n'ai pas traduit la page de wikipédia sur la programmation littéraire pour rien. Je me fais aussi avocat des commentaires plus longs que le code !

        Il se trouve que les deux techniques de programmations qui m'ont le plus marquées sont celle de la programmation lettrée, et celle de Forth. L'une prône des commentaires très détaillés, l'autre un code qui est sa propre définition (Littéralement. En Forth, on « définit des mots » plutôt que d'écrire des fonctions.). C'est de Forth que je tiens mon habitude des fonctions très courtes (une fonction qui tient sur une ligne de 64 caractères, un module de 16 lignes, je trouve ça magique).

        • [^] # Re: Code auto-documenté

          Posté par  (site web personnel) . Évalué à 6.

          Je répond très vite (probablement plus détaillé plus tard).

          En fait je trouve que la recherche du "on remplace les commentaires par du code" complexifie le code.
          Regarde ce que tu as au final et ce qu'il y avait au début. Je trouve le code initial (même sans commentaires) plus simple à lire. Et ça en terme de maintenance, c'est très important.

          Mais surtout, tu essaies de faire dire au code le contenu des commentaires. Certes, on s'en approche. Mais une part de l'intention est toujours absente. Entre autre le fait que si on permet de charger plusieurs fois base.js (et donc deps en effet) c'est parce que des frameworks de tests font les choses un peu étrangement. Cette information demeure totalement absente. Certes certains pourraient dire que c'est une information peu pertinente. Mais finalement si on ne l'a pas, on ne peut pas savoir pourquoi on laisse passer. Enfin si, on sait dans quel cas (le cas où c'est chargé plusieurs fois) mais on ne sait pas comment ce cas arrive (car ce n'est pas normal). Il manque toujours un bout.

          Sinon, pour le reste, je referai un commentaire plus long après ;)

        • [^] # Re: Code auto-documenté

          Posté par  . Évalué à 3.

          il faut inférer le pourquoi. Le commentaire a l'avantage de prémacher le travail. Il a aussi l'inconvénient, parfois, de mettre notre cerveau sur off,

          Donc en gros on galère plus pour avoir moins d'information, dont certaines vitales et on peut facilement passer à côté alors que justement le but d'un commentaire de s'assurer que le lecteur à le contexte.

          Le jeu de piste c'est rigolo sur un exemple jouet, mininuscule et statique, comme celui-là. Maintenant sur du vrai code qui a une vraie vie je ne donne pas très cher de la survie des informations ni de leur efficacité.

          D'ailleurs en tant que lecteur, que tu refactorises ou non, je te maudirais si tu m'enlèves l'explication explicite sur le base.js.

          Quand on dit qu'un code bien écrit se passe de commentaires, c'est un peu comme dire qu'un texte bien écrit en anglais peut se passer de commentaires en français

          Je ne suis pas d'accord avec ca. Un commentaire c'est une note en bas de page qui explique un contexte, spécifie une particularité ou intension précise que le lecteur peut ne pas connaître. C'est peut être pas élégant ou idéal, mais l'important c'est avant tout d'avoir l'information. Et il y a beaucoup de cas ou si tu te l'interdit alors tu vas forcement en perdre.

          Lire du code c'est lire un vieux bouquin dans un domaine très pointu. Je te serais reconnaissant de me prendre pas la main par ce que bordel des lignes de code comme ca y'en a 500 000 dans 5 langages dans le repo…

  • # Bons commentaires

    Posté par  (site web personnel) . Évalué à 4.

    Le problème n'est pas tant de savoir s'il faut commenter le code ou non — oui il faut commenter le code! — mais de savoir quelle information doivent véhiculer les commentaires.

    Les commentaires qui paraphrasent le code sans rien expliquer ne servent à rien. Par exemple en C un commentaire de type

    /* returnPointer();
         Return a pointer.
     */
    my_structure* returnPointer();
    
    

    comme on en voit souvent, ne sert à rien: il manque l'information cruciale: qui possède le pointeur?

    Il faut toujours commenter le domaine des arguments acceptés, car en général le type seul ne permet pas déterminer le domaine de la fonction. Il faut aussi commenter les conditions d'erreur, particulièrement celles qui ne sont pas gérées. Les algorithmes doivent être commentés, sinon on n'y comprend rien! Les invariants doivent être écrits.

    En gros, il suffit d'avoir de la sympathie pour la personne qu'on sera dans 3 mois qui devra déboguer le code et aura tout oublié! :)

    P.S.: Sur la photo c'est quoi la fonte? On dirait Monaco mais je ne suis pas sûr à cause de la perspective. :)

    • [^] # Re: Bons commentaires

      Posté par  . Évalué à 1.

      Il faut toujours commenter le domaine des arguments acceptés, car en général le type seul ne permet pas déterminer le domaine de la fonction. Il faut aussi commenter les conditions d'erreur, particulièrement celles qui ne sont pas gérées.

      En gros, tu prônes la programmation par contrat?

      Celle-ci permets justement de virer pas mal de commentaires (enfin, pas trop pour le C, vu qu'on ne possède pas certains outils nativement comme les exceptions, mais…):

      "my_structure* returnPointer();"

      my_structure* returnPointer()
      {
      my_structure* ret;

      if(ret==NULL)
      generateSigSegv();
      }

      La, on sait que si on retourne NULL (0) on génère une sigsegv et le programme se plantera. Avant même d'essayer d'utiliser une valeur invalide, et pourtant je ne l'ai commenté nulle part.

      Ensuite, le nom est redondant avec la signature de la fonction: on sait déjà, grâce au code, que la fonction retourne un pointeur… grâce au prototype, on sait même de quel type, d'ailleurs. Par contre, rien ne nous indique sur quoi le pointeur pointe…
      my_structure* getVideoAddress() serait par exemple bien meilleur. On sait qu'on se récupère une adresse vidéo, sous forme d'une instance de type my_structure.

    • [^] # Re: Bons commentaires

      Posté par  (site web personnel) . Évalué à 2.

      P.S.: Sur la photo c'est quoi la fonte? On dirait Monaco mais je ne suis pas sûr à cause de la perspective. :)

      Ubuntu Mono (source : https://twitter.com/instacodez/status/327059408947392514)

  • # Allez, un exemple concret...

    Posté par  . Évalué à 3.

    Pour savoir si on doit commenter ou pas son code source, je me réfère toujours à un code de référence (par sa visibilité et l´échelle des déploiements) : le noyau Linux.

    Dans le code du noyau Linux, on vas trouver le code qui gère la mémoire virtuelle, qui gère le PCI, les interruptions, les périphériques USB, j´en passe et des meilleurs. Je n´y ai fait que de (trop) rares modifications pour m´y attarder.

    Ce que l´on sait moins, c´est qu´il y a aussi beaucoup de code accessoire, comme toute l´infrastructure qui permet de configurer et compiler le noyau.

    Et là, par contre, ça commence à devenir, comment dire, pour le moins folklo. Je conseille à tout un chacun de jeter un œil sur le code de kconfig pour voir l´étendue des dégâts dans un code non commenté, et ayant évolué de manière organique au fil du temps (10 ans au moins).

    Voilà, j´espère garder quelques cheveux après mes pérégrinations dans ce code… ;-)

    Hop,
    Moi.

  • # résumé

    Posté par  . Évalué à 2.

    pourquoi les éditeurs écrive des résumés derrière les livres, alors qu'un titre explicite devrait pouvoir donner toutes les informations sur le contexte, la trame, les personnes du dit-bouquin ?

    Meme combat avec les commentaires. Parfoit le noms de la fonction peut pas décrire tout ce qu'elle fait.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.