IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Débats sur le développement - Le Best Of Discussion :

Un code bien écrit a-t-il besoin des commentaires ?


Sujet :

Débats sur le développement - Le Best Of

  1. #361
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par Neckara Voir le message
    J'ai écrit il y a peu un code assez complexe pour retirer automatiquement les pierres inutiles à la fin d'une partie de Go.

    L'algorithme est très facile pour un humain mais pour l'écrire dans un langage, j'ai été obligé de me casser la tête pendant des jours entiers pour trouver des équivalences.

    Je pense donc qu'il est nécessaire d'expliquer dans les cartouches des fonctions l'algorithme "pas détaillé" pour expliquer pourquoi il fait ce qu'on voulait mais je pense aussi qu'il faille mettre dans le code quelques commentaires pour expliquer plus en détails quelques points d'algorithme rapidement.
    Dans le cartouche, là je n'ai aucun problème à ce que tu expliques de manière plus approfondie les choses utiles (voir une note proche de see also qui te ramène à une explication plus complète), mais pas dans le code

    Bien sûr mon code ne doit pas respecter correctement toutes tes règles donc je ne pourrais pas te le proposer en contre-exemple.
    Et pourtant, le principe pour y arriver est simple, même s'il en fait blêmir plus d'un :

    Tout concept qui apparait dans l'analyse des besoins / fonctionnelle ou technique mérite d'apparaitre dans le code, et, pour ce faire, en te basant sur un principe comme un nom (group sujet) = un type, un verbe (groupe verbal) = une fonction.

    Je me fous pas mal de savoir que le type est un alias sur un entier, une énumération, une structure C style, une classe ou une union! Il faut juste savoir que si tu as un nom qui représente un concept, ce nom mérite d'apparaitre dans le code

    Je me fous pas mal de savoir si la fonction est une fonction libre ou une fonction membre, si elle est publique, privée, statique ou virtuelle, il faut juste qu'elle existe

    En te posant la question "j'ai un type (ou une fonction) qui représente tel concept, mais quelle est sa responsabilité " et en veillant à ce que cette responsabilité soit unique, tu verras tout de suite si ton concept n'est pas "un peu trop général" et s'il n'est par conséquent pas utile de le préciser quelque peu, quitte à rajouter plusieurs concepts qui, eux aussi, seront représentés dans le code sous la forme d'un type ou d'une fonction plus spécifique, mais moins compliquée, et donc plus facilement maintenable et tout ce que tu veux .
    Après, il y a la théorie et la pratique. Une personne peut être sûre d'avoir respecté tous tes principes correctement mais un relecteur pourrait ne pas être de cet avis donc rajouter des commentaires à certaine ligne peut parfois aider (d'ailleurs qui peut affirmer n'écrire que du code respectant tous les bonnes pratiques de programmation?).
    Disons qu'il y a surtout des symptômes qui ne trompent pas quand tu ne les respecte pas:
    • Des fonctions "kilométriques" (qui dépassent allègrement la cinquantaine de lignes, même en admettant une certaine souplesse)
    • Des tests et des boucles imbriquées à n'en plus finir (mettons de manière plus ou moins arbitraire, plus de deux ou trois niveaux d'imbrication)
    • Des copier/coller de code "à quelques variantes près" (quand il y a des variantes ), que ce soit dans une même fonction, dans deux fonctions membre d'une même classe ou carrément dans deux fonctions totalement distinctes.
    • Des tests de transtypage récurrents
    • je pourrais surement encore en trouver, mais bon ...
    Tout cela doit te mettre quelque peu la puce à l'oreille, non
    J'ai par exemple écrit du code pour une entreprise qui sera sûrement repris par un stagiaire, ce dernier sera assez content d'avoir quelques commentaires.
    Et, dans les fonctions pour lesquels il serait content d'avoir des commentaires, si tu y réfléchis, il y a combien des indices dont je viens de dresser la liste (non exhaustive) qui te feraient penser que tu n'a peut etre pas assez factorisé / délégué ton code

    Bien sûr tout est histoire de proportion, il ne faut pas en abuser non plus.
    Dés le moment où il risque de ne pas être cohérent vis à vis du code, il n'a aucune raison d'être, purement et simplement.

    Et je vais une fois de plus répéter ma thèse pour ne laisser aucun doute :
    • Les cartouches, c'est quasiment obligatoire, dés le moment où l'on passe le stade d'un accesseur.
    • Les commentaires à visée pédagogique ou didactiques sont les bienvenus, quand on est dans tel contexte
    • Les commentaires qui font référence à un rapport de bogue sont également les bienvenus pour attirer l'attention du lecteur.
    • Mais les commentaires qui, de manière générale, paraphrasent le code n'ont strictement rien à faire dans le code vu que le code doit se suffire à lui-même

  2. #362
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    Je pense avoir compris comment tu raisonnes.

    Quand nous on ferait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int i = 0;
    
    i %= 4; //explication nécessaire du passage très compliqué
    
    i++;
    toi tu serais plus tenté par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /** explication nécessaire du passage très compliqué */
    int foo(int i)
    {
           return i%4;
    }
    
    int i = 0;
    i = foo(i);
    i++;
    où " explication nécessaire du passage très compliqué" est nécessaire à la bonne compréhension du code (grand exemple : "un groupe est vivant ssi il possède deux yeux potentiels ;" "un oeil potentiel : qui peut devenir un oeil <=> un espace entièrement délimité par des groupes de pierres alliées vivants avec à l'intérieur l'impossibilité pour l'adversaire d'entourer entièrement les pierres "frontières" du groupe observées même en faisant exprès de se faire "manger" ie les adversaires peuvent faire des "faux-oeils" => Si un groupe allier appartenant à cet espace peut être mangé alors il y a création d'un "faux-oeil" => si un groupe n'est pas vivant, l'espace n'est pas un oeil potentiel", là je pense qu'on ne m'en voudra pas si je rajoute quelques rappels dans le code ).


    Mais dans le cas d'algo assez complexes, on peut se retrouver avec pleins de petites fonctions qu'on ne sait même plus où mettre (avoir des classes de 50 méthodes ça fait beaucoup et dans ce cas là où rajouter les méthodes ?) et cela peut rendre le code beaucoup plus compliqué à "suivre" (personnellement pour un algorithme très "linéaire", j'aime bien avoir les 50/75 lignes sous les yeux plutôt que de devoir me balader de fonctions en fonctions).

    A moins que plutôt que tu préfères créer des classes pour un calcul particulier ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class CalculerModule
    {
               CalculerModule(...);
               Type result(void);
           private :
                //10 méthodes nécessaire au calculs
    
    }
    Et dans le cas où plusieurs "classes de calculs" ont besoins de méthodes similaires, tu fais une classe mère dont tu hérites en protected ou private (voir un pointeur vers une classe-outils ?).

    Je pars dans mon délire mais quand tu t'aperçois que les calculs que font ta classes sont plus long que prévus et que tu as besoin de "trop de méthodes", comment fais-tu pour conserver tout de même un nombre raisonnable de méthodes dans ta classe ?


    Sinon, on parle beaucoup des grand principe à respecter mais parmi ces "principes qu'on devrait respecter", font-il tous l'unanimité ? (ex : moins de 25 lignes par fonctions par exemple ).
    Sinon, je pense qu'il serait bien d'avoir un récapitulatif de toutes les bonnes méthodes, je sais qu'il y a SOLID (mais je vois moyennement à quoi correspond chaque lettres ), il y a les nommages explicites de variables (mais "nommage explicite" reste un peu flou, qu'appelle-t-on un "nommage explicite" et pour qui? ...)

    EDIT : d'ailleurs, serait-il possible d'avoir une archive d'un de tes projets "moyen/gros" ? En regardant comment tu as fait et comme nous, nous aurions fait, on pourra peut-être comprendre un peu mieux comment tu codes et donc mieux comprendre ton point de vue (?)

  3. #363
    Expert éminent
    Avatar de Matthieu Vergne
    Homme Profil pro
    Consultant IT, chercheur IA indépendant
    Inscrit en
    Novembre 2011
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant IT, chercheur IA indépendant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 2 272
    Points : 7 800
    Points
    7 800
    Billets dans le blog
    3
    Par défaut
    Cela dit tu explicites un point important Koala01 :
    Citation Envoyé par koala01 Voir le message
    Tout concept qui apparait dans l'analyse des besoins / fonctionnelle ou technique mérite d'apparaitre dans le code
    Encore faut-il passer le temps nécessaire à faire ces analyses correctement. Mais seul quelqu'un qui a déjà une bonne expérience du domaine peut le faire sans passer au codage entre temps. De plus, c'est en supposant qu'on laisse effectivement le temps nécessaire à ces analystes expérimentés.

    Là peut-être qu'on touche plus du doigt le théorie VS pratique : en pratique, les vrais experts qui peuvent établir ce genre d'analyse de manière robuste sont pas toujours sous la main. Tout le monde veut la perle rare, mais des fois il faut bien faire avec un jeunot qui n'a pas toute la bouteille nécessaire parce que c'est tout ce qu'on a réussi à avoir (e.g. petite boite pas connue et pas avec les bons contacts).

    Et même si on les a, si la boite met l'accent sur la soi-disant "productivité" en demandant des délivrables dans des délais trop serrés pour faire une analyse poussée, il y aura forcément des défauts d'analyse (descriptions incomplètes ou incohérentes). Et ces défauts apparaitront dans le code, où le programmeur devra trouver une solution le jour où il tombera dessus. Mais si le programmeur n'est pas l'analyste (où ne peut rien lui demander) on imagine aisément la divergence qui suit.

    Je vais pas développer plus, mais grosso-modo, un code "bien écrit" dans le sens où koala01 l'entends (et moi aussi d'ailleurs) implique au moins 2 choses :
    - que le dév soit déjà expérimenté (on l'a déjà dit, on ne parle pas d'un contexte d'apprentissage, d'abord on apprends, ensuite on produit)
    - que la mise en avant de la qualité du code soit suffisante pour pouvoir effectivement utiliser des bonnes pratiques

    On peut donc dire qu'on ne parle pas d'une utopie (ça reste tout à fait envisageable) mais c'est sûr que c'est pas un contexte qui court les rues de nos jours.

  4. #364
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je pense avoir compris comment tu raisonnes.

    Quand nous on ferait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int i = 0;
    
    i %= 4; //explication nécessaire du passage très compliqué
    
    i++;
    toi tu serais plus tenté par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /** explication nécessaire du passage très compliqué */
    int foo(int i)
    {
           return i%4;
    }
    
    int i = 0;
    i = foo(i);
    i++;
    où " explication nécessaire du passage très compliqué" est nécessaire à la bonne compréhension du code (grand exemple : "un groupe est vivant ssi il possède deux yeux potentiels ;" "un oeil potentiel : qui peut devenir un oeil <=> un espace entièrement délimité par des groupes de pierres alliées vivants avec à l'intérieur l'impossibilité pour l'adversaire d'entourer entièrement les pierres "frontières" du groupe observées même en faisant exprès de se faire "manger" ie les adversaires peuvent faire des "faux-oeils" => Si un groupe allier appartenant à cet espace peut être mangé alors il y a création d'un "faux-oeil" => si un groupe n'est pas vivant, l'espace n'est pas un oeil potentiel", là je pense qu'on ne m'en voudra pas si je rajoute quelques rappels dans le code ).
    As tu déjà compté le nombre de concepts que tu as introduit dans cette seule phrase on peut en dresser la liste, tu vas voir, c'est impressionnant, et je ne suis pas forcément sur d'avoir bien tout pris.
    • groupe
      • vivant
    • oeil potentiel
    • oeil
    • groupe de pierres alliées (bon, c'est peut etre le même que groupe)
    • pierre
    • frontière
    • se faire manger
    • faux-oeil

    Tu ne crois pas que chacun de ces concepts mérite amplement d'apparaitre dans ton code se faire manger et vivant sous la forme de fonction, les autres sous la forme de types (quels qu'ils soient)

    Si déjà tu donnes une responsabilité unique à ces différents concepts, tu te donnes l'occasion de simplifier énormément ton algorithme et, qui sait, de rendre chaque concept responsable d'une partie courte, simple et efficace du traitement
    Mais dans le cas d'algo assez complexes, on peut se retrouver avec pleins de petites fonctions qu'on ne sait même plus où mettre (avoir des classes de 50 méthodes ça fait beaucoup et dans ce cas là où rajouter les méthodes ?) et cela peut rendre le code beaucoup plus compliqué à "suivre"
    Je ne conseillerai jamais à quelqu'un de créer une classe avec 50 fonctions non plus, ne serait-ce parce que ce serait un symptome, justement, que la classe en fait trop et qu'il y a donc très vraisemblablement intérêt à en revoir la responsabilité
    (personnellement pour un algorithme très "linéaire", j'aime bien avoir les 50/75 lignes sous les yeux plutôt que de devoir me balader de fonctions en fonctions).
    Si l'algorithme est effectivement totalement linéaire et qu'il y a, effectivement, 50 ou 75 étapes à respecter l'une après l'autre, sans la moindre boucle, sans le moindre test pour passer d'un état A à un état B, cela ne me gène absolument pas que la fonction fasse 50 ou 75 lignes, mais, dans ce cas, où est le besoin de commentaire si chaque étape est "auto-commentée" et la "suite logique" de ce qui a été fait avant en vue de préparer l'étape suivante

    A moins que plutôt que tu préfères créer des classes pour un calcul particulier ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class CalculerModule
    {
               CalculerModule(...);
               Type result(void);
           private :
                //10 méthodes nécessaire au calculs
    
    }
    Et dans le cas où plusieurs "classes de calculs" ont besoins de méthodes similaires, tu fais une classe mère dont tu hérites en protected ou private (voir un pointeur vers une classe-outils ?).

    Je pars dans mon délire mais quand tu t'aperçois que les calculs que font ta classes sont plus long que prévus et que tu as besoin de "trop de méthodes", comment fais-tu pour conserver tout de même un nombre raisonnable de méthodes dans ta classe ?
    Tu parles d'un cas beaucoup trop abstrait pour que je puisse te répondre, présentes moi un besoin concret, et je m'adapterai
    Sinon, on parle beaucoup des grand principe à respecter mais parmi ces "principes qu'on devrait respecter", font-il tous l'unanimité ? (ex : moins de 25 lignes par fonctions par exemple ).
    Même à l'époque des écrans de 25 lignes par 80 colonnes, la règle acceptait 50 lignes (deux hauteurs d'écrans)

    Et c'est peut être le principe qui, par son coté arbitraire, est le plus contesté.

    Je préfères conseiller de garder "un nombre acceptable" de lignes: je citais la tantôt le chiffre de cinquante lignes, mais j'admettais "une certaine marge", sans préciser laquelle

    Mais il y a quand meme une différence entre créer une fonction de 75, voire de 100 lignes et essayer d'en avoir une de 650 lignes, comme j'en ai déjà vu!

    Personnellement, je dirais que la limite acceptable est que toute ta fonction doit pouvoir apparaitre à l'écran (dans ton EDI) sans avoir à jouer avec les scrollbars, pour que tu puisses l'avoir en permanence intégralement devant les yeux, et uniquement si tu ne commences pas à avoir plus de trois niveaux d'imbrication.

    Au delà, il me semble plus qu'utile d'essayer de voir s'il n'y a pas moyen de déléguer certaines tâches
    Sinon, je pense qu'il serait bien d'avoir un récapitulatif de toutes les bonnes méthodes, je sais qu'il y a SOLID (mais je vois moyennement à quoi correspond chaque lettres ),
    D'ici la mi novembre (allez, mettons début décembre pour être sûr), il y aura un bouquin (écrit par votre serviteur )qui les reprendra, les expliquera et les justifiera

    Il se fend même d'une étude de cas complète dans laquelle j'implémente toute la logique d'un jeu d'échecs (hors intelligence artificielle) en ligne de commande, prêt à évoluer vers n'importe quelle interface graphique et ce, en moins de 3000 lignes de code (2621 lignes de code pour être précis et... 1238 lignes de cartouches )
    il y a les nommages explicites de variables (mais "nommage explicite" reste un peu flou, qu'appelle-t-on un "nommage explicite" et pour qui? ...)
    un nommage explicite doit permettre à n'importe quel développeur arrivant sur du code, soit parce qu'il "débarque sur le projet", soit parce qu'il revient dessus après six mois, de se faire une idée claire de la raison d'être, du but et de l'utilité de la variable, de la fonction ou du type qu'il rencontre.

    Il ne sert très certainement à rien de faire des noms à rallonge et à charnière comme en présentait r0d il y a quelques message (object_that_contains_the_logic_of_the_application), mais il reste malgré tout préférable d'éviter les abréviations dont le sens pourrait échapper à quelqu'un(FSM()::SS( logic.RSL.s );, toujours pour citer r0d )

    Il y a généralement moyen de trouver un juste milieu en fonction du contexte dans lequel on se trouve

    Je n'aurais, par exemple, absolument rien contre le fait d'avoir une classe nommé BnfNode si je suis dans un contexte où je dois travailler avec un grammaire respectant les règles de la Backus-Naur Form si c'est pour faire la distinction entre ce type de noeud particulier et d'autres noeuds que j'utilise dans le même projet(mais dans d'autres contextes)

    Cela irait, bien sur, de pair avec un cartouche qui indiquerait clairement que ce noeud est utilisé dans le contexte de la grammaire BNF et en quoi il serait différent des autres noeuds

    [EDIT]J'admets volontiers que c'est très subjectif, mais, combien de fois as-tu toi-même pesté sur ce forum même contre les gens qui utilisaient des noms qui ne t'invoquaient rien

    Poses toi peut etre simplement la question de savoir :
    si je présente mon code sur le forum, est-ce que les gens comprendront le but et la raison d'être de ma fonction, de ma classe ou de ma variable
    Cela te donneras très certainement une idée bien claire de ce qu'est un nom explicite

  5. #365
    Expert éminent
    Avatar de Matthieu Vergne
    Homme Profil pro
    Consultant IT, chercheur IA indépendant
    Inscrit en
    Novembre 2011
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant IT, chercheur IA indépendant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 2 272
    Points : 7 800
    Points
    7 800
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Mais dans le cas d'algo assez complexes, on peut se retrouver avec pleins de petites fonctions qu'on ne sait même plus où mettre (avoir des classes de 50 méthodes ça fait beaucoup et dans ce cas là où rajouter les méthodes ?) et cela peut rendre le code beaucoup plus compliqué à "suivre" (personnellement pour un algorithme très "linéaire", j'aime bien avoir les 50/75 lignes sous les yeux plutôt que de devoir me balader de fonctions en fonctions).
    Citation Envoyé par Neckara Voir le message
    Je pars dans mon délire mais quand tu t'aperçois que les calculs que font ta classes sont plus long que prévus et que tu as besoin de "trop de méthodes", comment fais-tu pour conserver tout de même un nombre raisonnable de méthodes dans ta classe ?
    Après c'est une question d'organisation : quand tu utilises un EDI qui t'affiche le cartouche de la fonction sur laquelle tu pointe et que tu peux aller directement à la définition de la fonction par un raccourci clavier, tu te fiches un peu d'avoir même 2000 fonctions posées aléatoirement dans ton code. Une classe n'a pas pour vocation à être lue comme un livre mais à être compilées. Cela dit, si tu es capable de nommer efficacement tes fonctions, c'est que tu sais identifier leur rôle. Il en est de même pour les classes. Donc savoir faire l'un correctement mais pas l'autre, perso j'y crois pas (après c'est pareil : faut prendre le temps nécessaire pour le faire correctement).

    Quand tu dois tout faire à la main, c'est sûr que ça demande plus de temps à consacrer au rangement et donc moins au codage, mais après il faut savoir utiliser les outils à disposition : faire un tri par insertion est plus simple en manu, mais un quick-sort est plus efficace. Si tu ne te donnes pas les moyens de faire un quick-sort facilement, c'est sûr que tu restera avec un tri par insertion. L'idée est la même ici : quand tu fais des choses complexes, utilise des outils qui te permettent de simplifier les processus pour te concentrer sur l'essentiel. Les algos plus efficaces sont généralement plus complexes, y'a pas de "free-lunch" comme on dit. Les bonnes pratiques c'est pareil, faut se donner les moyens de pouvoir les appliquer facilement (bosser dans une équipe qui nous laisse les appliquer en est un).

    Citation Envoyé par Neckara Voir le message
    Sinon, on parle beaucoup des grand principe à respecter mais parmi ces "principes qu'on devrait respecter", font-il tous l'unanimité ? (ex : moins de 25 lignes par fonctions par exemple ).
    Sinon, je pense qu'il serait bien d'avoir un récapitulatif de toutes les bonnes méthodes, je sais qu'il y a SOLID (mais je vois moyennement à quoi correspond chaque lettres ), il y a les nommages explicites de variables (mais "nommage explicite" reste un peu flou, qu'appelle-t-on un "nommage explicite" et pour qui? ...)
    - Font-il tous l'unanimité ? Non, jamais. Un principe n'est valable que parce que certaines hypothèses sont posées, donc dans un contexte spécifique. Certains principes peuvent être plus généralisables que d'autres, comme les conventions de nommage, mais ce n'est jamais applicable partout (e.g. d'anciens langages ne prenant pas des noms de plus de x caractères ne peuvent pas permettre ces conventions de nommage moderne). De même, l'utilisation du CamelCase permet sous Eclipse de parcourir les noms plus aisément, mais d'autres EDI peuvent favoriser d'autres conventions de nommage. Donc si déjà pour une convention aussi simple on a des variances, prôner l'unanimité n'est même pas à l'ordre du jour. L'important est plus d'être cohérent dans ses conventions (en choisir des bonnes relativement à son contexte et les appliquer de manière continue).

    - Qu'appelle-t-on un "nommage explicite" et pour qui ? Explicite veut dire dont on ne peut avoir qu'une seule interprétation (on ne peut donc pas se tromper sur sa compréhension). Je ne vais pas entre dans les détails des concepts et ontologies, mais l'interprétation dépend toujours des connaissances du lecteur. À la question "pour qui" on ne pourra donc jamais y répondre "pour tout le monde". Donc tout comme la question précédente, il n'y a pas d'unanimité sur ce qui est explicite et ce qui ne l'est pas. Dans un domaine particulier, certains concepts sont communément reconnus avec un sens bien précis (e.g. en maths, un plan est un espace en 2D, en architecture c'est un dessin, en entreprise c'est une suite d'étapes), on peut donc les prendre comme explicite tant qu'on suppose que ce sont des gens du même domaine qui le liront. En dehors, on ne peut qu'espérer que l'interprétation du lecteur sera assez proche du sens qu'on veut donner. C'est d'ailleurs pour ça qu'il est inutile de critiquer un code en disant "et si je donne ton code au premier venu est-ce qu'il le comprendra ?", pour la simple raison que la réponse ne pourra jamais être oui, malgré tout le soin qu'on pourra y apporter.

    Citation Envoyé par Neckara Voir le message
    EDIT : d'ailleurs, serait-il possible d'avoir une archive d'un de tes projets "moyen/gros" ? En regardant comment tu as fait et comme nous, nous aurions fait, on pourra peut-être comprendre un peu mieux comment tu codes et donc mieux comprendre ton point de vue (?)
    Pour ma part (des fois que ça intéresserai quelqu'un) j'ai bien un dépot Github mais j'y ai surtout des projets expérimentaux (qui ne sont plus tous jeunes d'ailleurs), où l'analyse se fait au fur et à mesure du codage. Cela dit, j'essayais déjà d'avoir un code clair. Le plus gros projet (et le seul finalisé il me semble) c'est l'automate cellulaire (cellular automaton). Bien entendu, comme justifié précédemment, il faut déjà savoir ce qu'est un automate cellulaire avant d'aller y faire un tour {^_^}.

  6. #366
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    Citation Envoyé par koala01 Voir le message
    As tu déjà compté le nombre de concepts que tu as introduit dans cette seule phrase on peut en dresser la liste, tu vas voir, c'est impressionnant, et je ne suis pas forcément sur d'avoir bien tout pris.
    • groupe
      • vivant
    • oeil potentiel
    • oeil
    • groupe de pierres alliées (bon, c'est peut etre le même que groupe)
    • pierre
    • frontière
    • se faire manger
    • faux-oeil

    Tu ne crois pas que chacun de ces concepts mérite amplement d'apparaitre dans ton code se faire manger et vivant sous la forme de fonction, les autres sous la forme de types (quels qu'ils soient)
    Je me suis mal exprimé.
    Celui qui va lire notre code va savoir qu'un "groupe vivant est a groupe qui a deux yeux potentiels". Mais il ne va pas forcément comprendre comment on détermine qu'un groupe a "deux yeux potentiels".
    Il va comprendre ce que fait le code mais pas pourquoi on le fait.
    Il faut donc par exemple, lui expliquer que "si un groupe allier peut être manger" implique "cet espace n'est pas un œil potentiel".

    Si on fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( aFriendGroupCanBeEat)
    {
          m_cantBeAnEye = false;
    }
    Il comprendra ce qu'on fait mais n'en comprendra pas la logique.
    Donc ajouter un petit commentaire pour lui expliquer par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( aFriendGroupCanBeEat) // un allier peut être mangé <=> l'adversaire peut avoir une liberté non-adjacente du groupe étudié.
    {
          m_cantBeAnEye = false;
    }
    Avec "l'adversaire peut avoir une liberté non-adjacente du groupe étudié." une condition expliquée dans le cartouche de la fonction.


    Si déjà tu donnes une responsabilité unique à ces différents concepts, tu te donnes l'occasion de simplifier énormément ton algorithme et, qui sait, de rendre chaque concept responsable d'une partie courte, simple et efficace du traitement.
    J'arrive à repérer les différents concepts mais mal à leur associer une responsabilité "unique".
    Par exemple, quelle responsabilité donner à un oeil ?
    De plus, on peut avoir une responsabilité unique comme supprimer les pierres inutiles mais cela me fera plus de 1500 lignes (environ).
    Il faut donc déléguer des "sous-responsabilité" je suppose.
    Mais comment bien faire ceci ?
    Prenons le cas d'une classe de résolution d'équation, on va avoir plusieurs possibilités :
    - créer un membre privé (ex : creerArbreOperation(const std::string) )
    - créer une nouvelle classe (ex : ArbreOperation ) ?;
    - ajouter un membre privé à une classe existante ( ArbreOperation::searchX() );
    Mais comment faire le bon choix ?
    creerArbreOperation(const std::string), pourquoi ne pas utiliser une factory ou la remplacer par une méthode de ArbreOperation ?
    ArbreOperation::searchX(), pourquoi ne pas avoir une "classe de recherche" ? ou faire une méthode pour notre classe d'équation qui ferait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for( auto noeud : arbre)
    {
              if(noeud.estInconnu() )
                    ; // TODO
    }
    où est le besoin de commentaire si chaque étape est "auto-commentée" et la "suite logique" de ce qui a été fait avant en vue de préparer l'étape suivante
    Je pense qu'on s'y retrouve un peu plus facilement en mettant un petit commentaire avant chaque "étape". Ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //vérifications (des pré-conditions par exemple)
    if( ....... )
             return false;
    if( ....... )
             return false;
    int i = foo(...);
    if( i <= 5 && i >= 4)
             return false;
    
    // fusion de l'arbre
    e = action1(a,b);
    f = action2(b, c);
    action3(e, f);
    
    // manque d'inspiration
    .????
    ????
    Dans ce code là, je peux le parcourir très rapidement et en comprendre vite fait l'algorithme général et retrouver un endroit facilement grâce aux "blocs" et aux commentaires.

    Tu parles d'un cas beaucoup trop abstrait pour que je puisse te répondre, présentes moi un besoin concret, et je m'adapterai
    C'est justement cela le problème, on essaye de trouver que faire dans un cas "général" mais seul le contexte peut donner la réponse à la question.
    Donc au final, les personnes non-expérimentée (comme moi) ne savent pas quoi faire
    Et si on donne du code, on aura la réponse pour un cas particulier mais à la prochaine rencontre de ce problème, on ne saura pas si la solution du cas particulier conviendrait au cas présent.

    Par exemple, je me fait une classe pour "supprimer les pions inutiles". Je m’aperçoit que mes fonctions sont assez longue/compliquées donc je vais factoriser un peu, et créer des petites fonctions private. Mais je me retrouve avec pleins de petites fonctions que je ne sais même plus comment nommer avec des méthodes portant le même nom mais ne correspondant pas du tout à la même partie de l'algorithme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void removeDeadGroup(void)
    {
             group = findDead();
             removeDeadGroup(group);
    }
    Comme je suis bien embêté, je vais tenter de me débarrasser de certaines méthodes en les plaçant dans d'autres classes (ex. removeDeadgroup(group) => Group::removeGroups(group) ). Et puis si y'en a trop, je vais tenter de me créer une classe avec les méthodes qui me semblent "aller bien ensembles" (souvent une classe avec pas mal de membres statiques d'ailleurs)


    D'ici la mi novembre (allez, mettons début décembre pour être sûr), il y aura un bouquin (écrit par votre serviteur )qui les reprendra, les expliquera et les justifiera
    Tu fais des réductions pour le père noël ?
    Plus sérieusement, est-ce qu'il est possible d'avoir par MP plus de détails (pré-commandes, etc...)

    EDIT :
    Pour ma part (des fois que ça intéresserai quelqu'un) j'ai bien un dépot Github mais j'y ai surtout des projets expérimentaux (qui ne sont plus tous jeunes d'ailleurs), où l'analyse se fait au fur et à mesure du codage. Cela dit, j'essayais déjà d'avoir un code clair. Le plus gros projet (et le seul finalisé il me semble) c'est l'automate cellulaire (cellular automaton). Bien entendu, comme justifié précédemment, il faut déjà savoir ce qu'est un automate cellulaire avant d'aller y faire un tour {^_^}.
    Je suis allé y faire un tour vite-fait, mais je ne comprend pas l'arborescence.
    Pourquoi avoir :
    neuralnetwork-samples / src / main / java / org / neuralnetwork / sample / booleanfunction /

    Alors que neuralnetwork ne contient en tout que 7 fichiers dont 5 dans booleanfunction ?
    Me cela me fait penser qu'il faudrait que je poste un sujet sur la question des arborescences aussi

  7. #367
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je me suis mal exprimé.
    Celui qui va lire notre code va savoir qu'un "groupe vivant est a groupe qui a deux yeux potentiels". Mais il ne va pas forcément comprendre comment on détermine qu'un groupe a "deux yeux potentiels".
    Il va comprendre ce que fait le code mais pas pourquoi on le fait.
    Il faut donc par exemple, lui expliquer que "si un groupe allier peut être manger" implique "cet espace n'est pas un œil potentiel".

    Si on fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( aFriendGroupCanBeEat)
    {
          m_cantBeAnEye = false;
    }
    Il comprendra ce qu'on fait mais n'en comprendra pas la logique.
    Donc ajouter un petit commentaire pour lui expliquer par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( aFriendGroupCanBeEat) // un allier peut être mangé <=> l'adversaire peut avoir une liberté non-adjacente du groupe étudié.
    {
          m_cantBeAnEye = false;
    }
    Avec "l'adversaire peut avoir une liberté non-adjacente du groupe étudié." une condition expliquée dans le cartouche de la fonction.



    J'arrive à repérer les différents concepts mais mal à leur associer une responsabilité "unique".
    Par exemple, quelle responsabilité donner à un oeil ?
    Autant le dire tout de suite, je ne connais absolument pas les règles du jeu de go, donc je ne pourrai répondre que de manière générale.

    Mais bon, commence peut être "simplement" par te demander ce que tu attends de la part de ton oeil, et en quoi il diffère de la notion d'oeil potentiel.

    Si, dans l'explication que tu vas donner du role de l'oeil, tu utilises des termes génériques comme "gérer", "contrôler" ou "manipuler" (liste non exhaustive ), essaye de préciser ces termes afin d'en sortir un ou plusieurs concept(s) plus simple(s) qui pourront sans doute être délégués: la "gestion" comprend très certainement le fait de garder une trace des différents objet, avec tout ce que cela sous entend d'ajout, de suppression et de recherche éventuelles, mais cela comprend aussi le fait de créer les objets et, pourquoi pas, de décider (ou non) qu'il est temps de les détruire

    Commence par te demander ce que signifie le groupe verbal "etre mangé" (ou "manger une pierre", cela revient au même).

    Poses toi la question de savoir quelles conditions doivent être remplies pour qu'une pierre puisse être mangée.

    Poses toi la question de savoir qui ou quoi décide qu'une pierrepeut être mangée ou non.

    Si tu as l'impression que tu seras tenté de donner cette responsabilité à "quelque chose" qui a déjà une responsabilité bien définie qui n'est pas de prendre ce genre de décision (typiquement à un oeil ou à un oeil potentiel), n'est ce pas le symptôme qu'il faut déléguer le respect du respect des règles (de manière générale) à un nouveau concept (typiquement le concept de "système d'arbitrage", dont il faudra préciser les différents aspects qui mèneront sans doute à de nouveau concepts à représenter sous la forme de types ou de fonctions)

    De plus, on peut avoir une responsabilité unique comme supprimer les pierres inutiles mais cela me fera plus de 1500 lignes (environ).
    Ah, si tu mélange dans une seule et même fonction le fait de déterminer si une pierre est utile (qui comprend lui-même le fait de s'intéresser à tout ce qu'il y a autour pour arriver à donner la réponse) avec le fait de parcourir l'ensemble du terrain de jeu pour effectivement supprimer les pierres inutiles, effectivement, tu vas sans doute te retrouver avec un code particulièrement long
    Il faut donc déléguer des "sous-responsabilité" je suppose.
    ouaip
    Mais comment bien faire ceci ?
    Je viens sans doute de t'en donner un aperçu relativement correct
    Prenons le cas d'une classe de résolution d'équation, on va avoir plusieurs possibilités :
    - créer un membre privé (ex : creerArbreOperation(const std::string) )
    - créer une nouvelle classe (ex : ArbreOperation ) ?;
    - ajouter un membre privé à une classe existante ( ArbreOperation::searchX() );
    Mais comment faire le bon choix ?
    creerArbreOperation(const std::string), pourquoi ne pas utiliser une factory ou la remplacer par une méthode de ArbreOperation ?
    ArbreOperation::searchX(), pourquoi ne pas avoir une "classe de recherche" ? ou faire une méthode pour notre classe d'équation qui ferait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for( auto noeud : arbre)
    {
              if(noeud.estInconnu() )
                    ; // TODO
    }
    On passe à un cas tout à fait différent, mais, en gros, une équation n'est jamais qu'un arbre binaire composé d'opérateurs (à définir) et d'opérande (qui peuvent être des expressions baties sur le modèle de un opérateur dispose de deux opérandes)

    Ce ne sont pas les exemples qui manquent
    Je pense qu'on s'y retrouve un peu plus facilement en mettant un petit commentaire avant chaque "étape". Ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //vérifications (des pré-conditions par exemple)
    if( ....... )
             return false;
    if( ....... )
             return false;
    int i = foo(...);
    if( i <= 5 && i >= 4)
             return false;
    Tu ne crois pas que la condition (que tu as si habilement remplacée par des pointillés ) puisse se suffire à elle-même lorsqu'on voit qu'elle retourne false
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // fusion de l'arbre
    e = action1(a,b);
    f = action2(b, c);
    action3(e, f);
    
    // manque d'inspiration
    .????
    ????
    Dans ce code là, je peux le parcourir très rapidement et en comprendre vite fait l'algorithme général et retrouver un endroit facilement grâce aux "blocs" et aux commentaires.
    Si action1, action2 et action3 portent des noms explicite, quel besoin auras tu d'indiquer que tu arrives au niveau de la fusion de l'arbre le code le dira de lui-même
    C'est justement cela le problème, on essaye de trouver que faire dans un cas "général" mais seul le contexte peut donner la réponse à la question.
    Donc au final, les personnes non-expérimentée (comme moi) ne savent pas quoi faire
    C'est, quelque part, le rôle d'un forum comme celui-ci: on te donnes des pistes, on essaye de t'expliquer le pourquoi et le comment des choses, et tu gagnes en expérience
    Et si on donne du code, on aura la réponse pour un cas particulier mais à la prochaine rencontre de ce problème, on ne saura pas si la solution du cas particulier conviendrait au cas présent.
    Tout dépendra de ton interlocuteur

    Par exemple, je me fait une classe pour "supprimer les pions inutiles". Je m’aperçoit que mes fonctions sont assez longue/compliquées donc je vais factoriser un peu, et créer des petites fonctions private. Mais je me retrouve avec pleins de petites fonctions que je ne sais même plus comment nommer avec des méthodes portant le même nom mais ne correspondant pas du tout à la même partie de l'algorithme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void removeDeadGroup(void)
    {
             group = findDead();
             removeDeadGroup(group);
    }
    Comme je suis bien embêté, je vais tenter de me débarrasser de certaines méthodes en les plaçant dans d'autres classes (ex. removeDeadgroup(group) => Group::removeGroups(group) ). Et puis si y'en a trop, je vais tenter de me créer une classe avec les méthodes qui me semblent "aller bien ensembles" (souvent une classe avec pas mal de membres statiques d'ailleurs)
    C'est là que l'on se rend compte qu'un minimum d'analyse est malgré tout indispensable.

    Tu es sans doute parti de l'idée "tiens, si je faisais un jeu de Go".

    La première question à se poser aurait sans doute été "c'est très bien, mais un jeu de Go, c'est quoi"
    La réponse à cette question aurait très certainement pris la forme de "c'est un jeu dans lequel (x) joueurs se confrontent en respectant certaines règles"

    Cela t'aurais sans doute naturellement incité à dresser la liste des règles à respecter, et cela t'aurais sans doute fait prendre conscience du fait que, à coté des joueurs, il devrait surement y avoir "quelque chose" chargé de les faire respecter.

    Et, à chaque fois que tu aurais introduit un nouveau concept (le concept de pierre, d'oeil ou d'oeil potentiel pour ne citer qu'eux), tu aurais pu / du les exprimer clairement : qu'est ce qu'ils font , pourquoi , comment , quelles sont leurs relation avec les autres concepts , et ainsi de suite

    Il ne faut surtout pas éviter à préciser des concepts qui semblent même très simples, comme le fait que se déplacer signifie "quitter une position pour accéder à une autre", car c'est très bien de dire à un objet qu'il doit aller vers une autre position, mais il y a peut etre "quelque chose à faire" du coté de la position qu'on vient de quitter

    Au final tu te serais retrouvé avec un certain nombre de concepts plus ou moins complexes (comme le concept d'oeil, de groupe ou de "système d'arbitrage") et d'autres beaucoup plus simples comme la notion de couleur ou de coordonnée, et chacun de ces concepts aurait pu prendre une responsabilité unique, "basique" pour les concepts les plus simples de couleur ou de coordonnée, de plus en plus complexes pour les concepts intermédiaires jusqu'à arriver à la notion de partie, de système d'entrées et de système de sortie qui permettent d'apporter l'interactivité indispensable à n'importe quel jeu

  8. #368
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    Si action1, action2 et action3 portent des noms explicite, quel besoin auras tu d'indiquer que tu arrives au niveau de la fusion de l'arbre le code le dira de lui-même
    Quand je vais revenir pour regarder cette fonction et que je recherche une partie en particulier, je regarde le début de la ligne de chaque bloc pour voir le commentaire et me repérer beaucoup plus facilement.
    (Sinon je pourrais mettre des labels pour ne mettre que du code )

    Je trouve que c'est plus rapide que de compter le nombre de "bloc" ou de regarder le contenu du bloc pour me re-situer.

    Pour les concepts, je pense comprendre l'idée. Dès que je me replonge dans de la programmation, j'essayerais de poster un sujet dans AML pour essayer de repérer les "concepts" (j'ai trop de choses à faire -de responsabilités si je peux me permettre ce jeu de mot - pour le faire maintenant).

  9. #369
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Quand je vais revenir pour regarder cette fonction et que je recherche une partie en particulier, je regarde le début de la ligne de chaque bloc pour voir le commentaire et me repérer beaucoup plus facilement.
    (Sinon je pourrais mettre des labels pour ne mettre que du code )

    Je trouve que c'est plus rapide que de compter le nombre de "bloc" ou de regarder le contenu du bloc pour me re-situer.
    Si ce sont vraiment des blocs particuliers, il y a des chances pour que ta fonction en fasse décidément trop, et donc que tu puisses envisager d'en déléguer certaines parties à des fonctions plus spécifiques.

    Pour reprendre ton exemple, on peut estimer que les préconditions seront communes à ta classe et que tu finiras, tôt ou tard, par envisager de les tester dans la majeure partie des fonctions membres, parce qu'elle donnent un "GO/NO GO" à la tentative de parcourir ton arbre.

    De même, on peut estimer que la fusion de l'arbre est un processus particulier qui se suffit à lui-même et qui (je ne sais pas, je pose la question ) mérite peut etre de faire partie des services rendus par ta classe . Ce sera soit un comportement interne (partagé ou non avec le classes dérivées, s'il y en a), soit un service "cohérent" pour ta classe

    Ajoutes à cela que tu as tout intérêt à garder des fonctions particulièrement simples (qui ne font qu'une chose, mais qui le font bien) :

    Non seulement, quand tu es dans une fonction checkPreconditions, tu te doutes bien qu'elle ne va pas sortir le chien mais... vérifier si les préconditions sont remplies

    Mais en plus, cela te permet de tester beaucoup plus facilement les différents comportement : créer un scénario dans lequel les préconditions ne sont pas remplies et vérifier que ta classe réagit correctement face à se scénario sans qu'il y ait d'interférences avec d'autre notions "hors contexte" (par rapport au préconditions s'entend ) devient un jeu d'enfant

    A l'inverse, si tes préconditions sont dans une fonction qui doit faire le café, sortir le chien et faire la vaisselle et qui risque de renvoyer false aussi bien parce que les préconditions ne sont pas remplies que parce qu'elle n'a pas pu faire tout ce qu'elle devait, comment faire la part des choses entre le false renvoyé pour condition non respectée et le false renvoyé pour cause d'action non effectuée

  10. #370
    Membre régulier
    Homme Profil pro
    .Net developer
    Inscrit en
    Février 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net developer

    Informations forums :
    Inscription : Février 2012
    Messages : 99
    Points : 91
    Points
    91
    Par défaut
    Citation Envoyé par koala01 Voir le message


    Montres moi un seul code qui respecte ces deux conditions et qui nécessite encore des commentaires pour aider le lecteur à le comprendre, et je changerai d'avis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #pragma config FOSC = INTIO67	// Internal oscillator block, port function on RA6 and RA7
    #pragma config PLLCFG = OFF	// Oscillator used directly 
    #pragma config PRICLKEN = OFF	// Primary clock can be disabled by software
    #pragma config FCMEN = OFF // Fail-Safe Clock Monitor disabled
    #pragma config PWRTEN = ON // Power up timer enabled
    #pragma config BOREN = OFF // Brown-out Reset disabled in hardware and software 
    #pragma config WDTEN = OFF // Watch dog timer is always disabled. SWDTEN has no effect
    #pragma config LVP = OFF // Single-Supply ICSP disabled 
    #pragma config MCLRE = EXTMCLR
    #pragma config IESO = OFF
    ça ne respecte peut-être pas vraiment tes 2 conditions. Toujours est-il qu'il n'est pas non plus envisageable de perdre de la mémoire pour faire des #DEFINE pour tous les registres à modifier.
    Meilleure idée que d'utiliser des commentaires?



    Une autre idée vient de me venir : en c#. J'ai du ré-écrire une classe qui créait des fichier icalendar, pour des clients à l'autre bout du monde. La manière de gérer les décallages horaires demande un peu de réflexion. Le fichier icalendar a un format bien particulier, avec des parties obligatoires, et d'autres optionnelles. Il y a des raisons à cela. Si je dois adapter certains trucs dans 1 an, j'ai pas envie de recommencer mes recherches, ni me casser le cul à re-comprendre certaines parties. Les commentaires sont obligatoires si je veux gagner en productivité.


    Avant d'être aussi catégorique que ce que tu ne l'es, essaye d'analyser le problème dans sa totalité.

  11. #371
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par patxy Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #pragma config FOSC = INTIO67	// Internal oscillator block, port function on RA6 and RA7
    #pragma config PLLCFG = OFF	// Oscillator used directly 
    #pragma config PRICLKEN = OFF	// Primary clock can be disabled by software
    #pragma config FCMEN = OFF // Fail-Safe Clock Monitor disabled
    #pragma config PWRTEN = ON // Power up timer enabled
    #pragma config BOREN = OFF // Brown-out Reset disabled in hardware and software 
    #pragma config WDTEN = OFF // Watch dog timer is always disabled. SWDTEN has no effect
    #pragma config LVP = OFF // Single-Supply ICSP disabled 
    #pragma config MCLRE = EXTMCLR
    #pragma config IESO = OFF
    Tu vas peut etre me taxer de mauvaise foi, mais tu trouves que, sortis de leur contexte, des termes comme FOSC, PLLCFG, PRICLKEN et tous les autres sont suffisamment explicites pour éviter tout malentendu de la part de celui qui lit le code

  12. #372
    Expert éminent
    Avatar de Matthieu Vergne
    Homme Profil pro
    Consultant IT, chercheur IA indépendant
    Inscrit en
    Novembre 2011
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant IT, chercheur IA indépendant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 2 272
    Points : 7 800
    Points
    7 800
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je suis allé y faire un tour vite-fait, mais je ne comprend pas l'arborescence.
    Pourquoi avoir :
    neuralnetwork-samples / src / main / java / org / neuralnetwork / sample / booleanfunction /

    Alors que neuralnetwork ne contient en tout que 7 fichiers dont 5 dans booleanfunction ?
    Parce que c'est une structure Maven (src/main/java = dossier des sources, main me rappelle plus, java pour les sources en Java) et un chemin de package java (org/neuralnetwork/sample/booleanfunction = nom du projet -j'aurais pu mettre fr/matthieuvergne/neuralnetwork-, sample pour identifier les examples, booleanfunction pour un exemple particulier). Ce sont des conventions de nommage qui, comme expliqué plus haut, correspondent à un contexte particulier et suivent des principes spécifiques. Si on y est familier, on comprend les avantages, si on ne l'est pas...

    Pour revenir à ton projet, je connais le Go (et j'ai d'ailleurs un projet dessus, faudrait que je le mette sur mon dépôt). Si ça t'intéresse Neckara je peux jeter un coup d'oeil à ton code s'il est open source.

  13. #373
    Expert éminent
    Avatar de Matthieu Vergne
    Homme Profil pro
    Consultant IT, chercheur IA indépendant
    Inscrit en
    Novembre 2011
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant IT, chercheur IA indépendant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 2 272
    Points : 7 800
    Points
    7 800
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par patxy Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #pragma config FOSC = INTIO67	// Internal oscillator block, port function on RA6 and RA7
    #pragma config PLLCFG = OFF	// Oscillator used directly 
    #pragma config PRICLKEN = OFF	// Primary clock can be disabled by software
    #pragma config FCMEN = OFF // Fail-Safe Clock Monitor disabled
    #pragma config PWRTEN = ON // Power up timer enabled
    #pragma config BOREN = OFF // Brown-out Reset disabled in hardware and software 
    #pragma config WDTEN = OFF // Watch dog timer is always disabled. SWDTEN has no effect
    #pragma config LVP = OFF // Single-Supply ICSP disabled 
    #pragma config MCLRE = EXTMCLR
    #pragma config IESO = OFF
    Là c'est plus comparable à un cartouche : à quoi servent tes variables. C'est comme avoir une fonction nommée de manière occulte et d'avoir un cartouche qui dit à quoi sert ta fonction... et là tu te rends peut-être compte que tu pourrais la nommée autrement.

  14. #374
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    Citation Envoyé par Matthieu Vergne Voir le message
    Pour revenir à ton projet, je connais le Go (et j'ai d'ailleurs un projet dessus, faudrait que je le mette sur mon dépôt). Si ça t'intéresse Neckara je peux jeter un coup d'oeil à ton code s'il est open source.
    Si tu n'as pas peur pour tes yeux, envois-moi un MP pour me dire comment tu veux que je t'envois les sources

    @Koala :
    Là ce n'était qu'un exemple, mais je découpe très souvent mes fonctions qui n'ont pas de if/while imbriqués en des petits blocs de 5-10 lignes.

    Si je devais faire une fonction pour chacun de ces blocs, je me retrouverais plus qu'avec des fonctions de 5 lignes et je serais bien embêté pour tenter de créer de nouvelles classes pour déléguer quelques méthodes de ma classe

  15. #375
    Membre régulier
    Homme Profil pro
    .Net developer
    Inscrit en
    Février 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net developer

    Informations forums :
    Inscription : Février 2012
    Messages : 99
    Points : 91
    Points
    91
    Par défaut
    Citation Envoyé par Matthieu Vergne Voir le message
    Là c'est plus comparable à un cartouche : à quoi servent tes variables. C'est comme avoir une fonction nommée de manière occulte et d'avoir un cartouche qui dit à quoi sert ta fonction... et là tu te rends peut-être compte que tu pourrais la nommée autrement.
    Tiens, si t'as du temps à perdre, tu peux aller voir la doc
    http://ww1.microchip.com/downloads/e...Doc/39564c.pdf


    Le code vient d'un projet que j'ai réalisé il y a plusieurs années. Si je me rappelle bien, ces instructions servent à configurer certains registres du microcontrôleur, avant la compilation.
    J'ai mis la doc pour que tu te rendes bien compte que des noms de registres, il y en a des centaines. Avec des configurations très spéciales.
    genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ANSELC = 0b01100000;  // ports 6 et 7 en analogiques
    ou encore l'écriture sur le LCD :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    							WriteCmdXLCD(0x01);	 //Clear LCD
    							while(BusyXLCD());
    							SetDDRamAddr(0x40);	 //2eme ligne
    							while( BusyXLCD());
    							putrsXLCD("Deconnecte");

    Si je me rappelle bien, le "processeur" utilisé était cadencé à 20mhz, et je n'avais en tout que 16kB pour stocker l'entièreté du code. Les 16KB servaient aussi de mémoire de travail.

    Il y avait un mini serveur web + des capteurs de t° et luminosité + mini clavier + écran LCD + des relais pour commander l'ouverture d'une porte.

  16. #376
    Expert éminent
    Avatar de Matthieu Vergne
    Homme Profil pro
    Consultant IT, chercheur IA indépendant
    Inscrit en
    Novembre 2011
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Consultant IT, chercheur IA indépendant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 2 272
    Points : 7 800
    Points
    7 800
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par patxy Voir le message
    Le code vient d'un projet que j'ai réalisé il y a plusieurs années. Si je me rappelle bien, ces instructions servent à configurer certains registres du microcontrôleur, avant la compilation.
    J'ai mis la doc pour que tu te rendes bien compte que des noms de registres, il y en a des centaines. Avec des configurations très spéciales.
    genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ANSELC = 0b01100000;  // ports 6 et 7 en analogiques
    Sauf que là, on est bien d'accord que tu cherches avant tout à optimiser les performances. La compréhension du code vient après. Non ?

    En mettant la compréhension du code avant, j'aurais plutôt fait quelque chose du genre (excuse de faire du Java, le C j'y ai pas touché depuis belle lurette) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Mode[] portModes = Mode[]{DIGITAL, DIGITAL, DIGITAL, DIGITAL, DIGITAL, ANALOGIC, ANALOGIC, DIGITAL}
    Où Mode est une énumération pouvant prendre les valeurs ANALOGIC ou DIGITAL (à supposer que ce soit bien le sens recherché, sinon à remplacer par ce qu'il faut). Après quoi j'aurai une fonction pour générer la valeur binaire correspondant à ces modes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Byte generateRegisterValueFor(Mode[] portModes) {...}
    L'idée étant que le binaire c'est le langage machine. Le programmeur travaille avec des concepts, pas des bits, et donc il n'a pas besoin de se surcharger de comprendre et utiliser une valeur binaire à moins qu'il ne s'intéresse à ce qui va être effectivement donné à la machine (mais dans ce cas il s'intéressera à la fonction qui génère les données machines, pas spécialement au contenu de la variable ou constante qui définit la configuration à appliquer).

  17. #377
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par patxy Voir le message
    ça ne respecte peut-être pas vraiment tes 2 conditions. Toujours est-il qu'il n'est pas non plus envisageable de perdre de la mémoire pour faire des #DEFINE pour tous les registres à modifier.
    Meilleure idée que d'utiliser des commentaires?
    Si tu m'avais fait cette réflexion il y a 30 ou 35 ans, quand le moindre bye de stockage valait son pesant de cacahuète et le moindre byte de mémoire son pesant d'or, que si tu voulais que ton projet tienne sur un stockage amovible il devait faire au total moins de 712 k, et que les processeurs atteignaient péniblement les 30Mhz, je n'aurais strictement rien eu à redire.

    Seulement, voilà, depuis on te jette les giga (aussi bien en terme de stockage qu'en terme de mémoire) à la figure, les processeurs pédalent un bon millier de fois plus vite et on a même inventé la compilation croisée.

    Il ne faut pas oublier que, tout ce qui passe par le préprocesseur sera, de toutes manières, transformer en valeur particulières, soit utilisées par le compilateur, soit "injectées" directement dans le code à la place du symbole équivalent, soit pour décider de laisser ou de retirer une portion de code.

    Au final, ton binaire n'aurait absolument pas souffert si tes noms avait été plus explicite

  18. #378
    Membre régulier
    Homme Profil pro
    .Net developer
    Inscrit en
    Février 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net developer

    Informations forums :
    Inscription : Février 2012
    Messages : 99
    Points : 91
    Points
    91
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Seulement, voilà, depuis on te jette les giga
    Regarde la doc que je t'ai envoyé. ça date de 2006... 30 ans tu dis?

    Tu manques juste énormément d'ouverture d'esprit. La programmation, ce n'est pas que destiné aux PC/GSM/...

  19. #379
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par patxy Voir le message
    Regarde la doc que je t'ai envoyé. ça date de 2006... 30 ans tu dis?

    Tu manques juste énormément d'ouverture d'esprit. La programmation, ce n'est pas que destiné aux PC/GSM/...
    Hé bien, ce code est, excuses moi de te le dire sous cette forme, honteux pour quelque chose d'aussi récent!

    Je faisais déjà de la compilation croisée depuis bien longtemps à cette époque!

    Si tu m'avais dit que tu courais après le moindre byte de mémoire ou de code dans les années 80, je n'aurais, comme je te l'ai dit, pu qu'approuver, mais il n'y a strictement rien qui t'obliges ni qui t'obligeais en 2006 de compiler spécifiquement sur la machine cible.

    Je comprends qu'en 2006, il fallait s'assurer que les binaires pour de l'embarqué soient les plus légers possibles, vu que c'est encore le cas maintenant.

    Mais ce qu'il faut bien se dire, c'est que les symboles préprocesseurs, quels qu'ils soient, n'interviennent qu'au niveau de la compilation et non au niveau de l'exécutable lui-même, vu qu'il sont, quoi qu'il arrive, évalués par le préprocesseur avant même que le compilateur ne commence à traiter le code.

    Tout se fait donc au niveau de la machine qui va compiler ton code pour fournir le binaire adapté à ta cible!

    Et je suis désolé, mais même en 2006, on avait largement dépassé le stade où une machine risquait de saturer parce qu'on définissait quelques symboles sur plus de 5 caractères.

    Si tu avais définis des symboles comme (pour reprendre la liste de ton code)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    INTERNAL_OCILLATOR_FUNCTION_ON
    USE_DIRECTLY_OSCILLIATOR
    PRIMARY_CLOCK_ENABLED
    FAIL_SAFE_CLOCK_MONITOR_ENABLED
    POWER_UP_TIMER_ENABLED
    BROWN_ON_RESETE_ENABLED
    WATCH_DOC_TIMER_ENABLED
    SINGLE_SUPPLY_ICSP_ENABLED
    /* désolé, je ne vois pas à quoi correspondent les deux derniers */
    quitte à les définir comme étant le symbole correspondant requis pour ton pragma, tu n'aurais absolument pas eu besoin des commentaires, et je peux t'assurer que ni ta machine de compilation ni ton binaire final n'aurait souffert d'avoir des symboles de 30 caractères

  20. #380
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 137
    Points
    23 137
    Par défaut
    @Koala : Je trouve que tu pinailles un peu.

    Il ne me semble pas qu'on ait à réutiliser nous même la valeur des #pragma configDonc de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #pragma config PLLCFG = OFF	// Oscillator used directly
    ou de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #define INTERNAL_OCILLATOR_FUNCTION_ON OFF
    #pragma config PLLCFG = INTERNAL_OCILLATOR_FUNCTION_ON
    reste tout de même assez équivalent.

    Et cela ne va pas tuer le compilateur ou le développeur si on met des commentaires non plus.

    Dans le cas où on configure certaines variables (exemple un timer quelconque) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void configureTimer0(bool repeat, int time, ...)
    {
          t0 = 1 << 7 // 8ème bit pour le mode repeat
                | /* d'autres trucs */
          t0d = time << 4; // premier quartet pour le temps restant
                                  // second quartet pour le temps déjà écoulé
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void configureTimer0(bool repeat, int time, ...)
    {
          t0 = REPEAT_MODE_ON;
          temps_ecoulé = 0;
          temps_restant = time;
          t0d = temps_restant << 4;
                  | temps_ecoulé;
    }
    J'invente bien sûr.

    Est-ce que ton refus des commentaires est vraiment justifié dans ce cas là ?
    Est-ce que les codes ne sont pas au final aussi lisibles l'un que l'autre ?

Discussions similaires

  1. Code Java bien écrit ?
    Par abysr dans le forum Débuter avec Java
    Réponses: 4
    Dernier message: 24/03/2015, 17h17
  2. Un code bien écrit a-t-il besoin des commentaires ?
    Par Hinault Romaric dans le forum Actualités
    Réponses: 334
    Dernier message: 19/07/2013, 15h22
  3. Un code bien commenté remplace-t-il une documentation? (+ gestion doc en entreprise)
    Par _skip dans le forum Débats sur le développement - Le Best Of
    Réponses: 30
    Dernier message: 13/01/2010, 13h12
  4. [Toutes versions] Identifier la base ACCESS où le code est écrit
    Par sl.info dans le forum VBA Access
    Réponses: 4
    Dernier message: 07/05/2009, 17h23
  5. [Système] Exécution code php écrit via fwrite()
    Par Torpedox dans le forum Langage
    Réponses: 4
    Dernier message: 26/01/2007, 18h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo