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

Langage C++ Discussion :

Que pensez-vous de la loi de Demeter ?


Sujet :

Langage C++

  1. #1
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut Que pensez-vous de la loi de Demeter ?
    Bonjour,
    Ceci fait suite à cette discussion .
    On peut trouver une définition assez complète de la loi de Demeter dans ce billet d'Emmanuel Deloget.
    En résumant, l'idée de la loi est de dire que dans une méthode m d'une classe A, je ne peux utiliser que :
    -> les méthodes de A (et ses classes de bases) ;
    -> les méthodes des membres de A ;
    -> les méthodes des paramètres de m ;
    -> les méthodes des objets créés par m ;
    -> les méthodes des variables globales.
    En revanche, cette loi sous-tend qu'on n'a pas de transition : on ne devrait pas utiliser :
    -> les méthodes des membres (ou des objets retournés par) des membres de A ;
    -> les méthodes des membres (ou des objets retournés par) les paramètres de m.
    etc.
    L'idée est qu'à travers cette loi, un objet masque à son utilisateur son contenu.
    Comme le note le billet, cette règle souffre d'exception : les structures triviales, les conteneurs et toutes sortes de fabriques pour des raisons évidentes.

    Pour reprendre les termes du débat :
    Citation Envoyé par JulienDuSud Voir le message
    cette loi est bien trop restrictive et amène souvent à de la redondance de code au niveau de la classe passerelle vis à vis de la classe source. D'ailleurs, en pratique cela donne trop de responsabilités à une classe.
    Souvent, quand cette loi n'est pas respectée, c'est que soit on expose des détails d'implémentation, soit on n'a pas le bon niveau d'abstraction. Et quand on n'a pas le bon niveau d'abstraction, on a l'impression que pour respecter la loi il faut transposer tout ce qui a dans la classe source à l'intérieur de la classe passerelle, ce que à quoi toutes nos fibres de C++eurs s'insurgent.

    Pensez-vous respecter cette loi ? La trouvez-vous trop contraignante ? Quand pensez-vous devoir la respecter et quand la violer ? Bref, quel est votre sentiment ?

  2. #2
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Comme je l'ai dit dans ma réponse initiale, je trouve cette loi très bien.

    Sauf que, en pratique, ça donne souvent l'obligation de créer des wrappers qui vont diviser l'indirection.

    L'exmple de Deloget est parlant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    edgeGroups.add(edge.getDirection().combine(edges));  // incorrect
    edgeGroups.add(combine(edge.getDirection(), edges)); // incorrect
    edgeGroups.add(edge.combineInSameDirection(edges));  // CORRECT
    On a du créer une méthode combineInSameDirection pour respecter la loi de Demeter.

    Si on veut combiner dans une autre direction que celui de edge, il faut utiliser la 2è méthode, qui ne respecte pas la loi car on récupère une direction via edge, et qu'on l'utilise.

    Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( otherEdge.getDirection(), edges ) );
    Qui ne respecte donc pas la loi.

    Ce qu'on doit faire, alors c'est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( otherEdge, edges ) );
    Et c'est edge qui doit récupérer la direction de otherEdge. En somme, pour respecter la loi de Demeter, on a déplacer du code.

    C'est très bien et facile à appliquer quand on a une association ternaire, mais que se passe-t-il à partir du moment où on a une association comprenant plus d'entités ?

    En essayant d'appliquer la loi à la lettre, on va se retrouver à créer des responsabilités là où il n'est pas nécessaire d'en avoir.

    Imaginons par exemple que edge est dépendant de Direction, comme dans l'exemple de Deloget.

    On va créer une classe fictive, Foo, qui dépendra également de Direction, dépendra non dans le sens hiérarchique, mais qui possède une instance de Direction.

    Et c'est là que le bas blesse:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( Foo, edges ) );
    edge ne connait pas Foo.

    On peut "bypass" le problème en créant une interface d'abstraction pour tous les objets qui possèdent une instance Direction.

    Résultat: on a de la redondance de code car l'implémentation de l'interface va se retrouver dans toutes les classes qui utilisent Direction.

    Il est hors de question d'avoir un héritage de Direction pour traiter le problème de redondance, vu que notre classe n'est PAS une direction, et ne doit pas être traité comme tel.

    Ceci n'est que ma pensée, et je n'ai pas été chercher trop loin, mais il me semble avoir été confronté à ce genre de problèmes lorsque je m'efforçais de respecter la loi de Demeter.

    Pour moi, la redondance de code c'est pire que le non respect d'une loi dans certains cas.

    Après, bien sûr, l'appliquer à chaque fois que c'est possible, c'est très très bien, chose d'ailleurs que je m'efforce de faire. Il est hors de question de laisser tomber cette loi qui apporte bien des choses pour la maintenance et pour l'évolution.

  3. #3
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Personnellement je ne la trouve pas assez sévère !

    En général je me retrouve avec deux sortes de code différents : le code bas niveau qui est du code générique pour mettre en place les briques de base, et le code de plus haut niveau très orienté objet qui assemble ces briques.
    Au fil du temps je me suis aperçu que le code de haut niveau finit par n'avoir presque que des méthodes qui retournent void, avec parfois un bool par-ci par-là, mais en tous cas aucun getter (et très peu de setters).

    Bref Demeter oui bien sûr, mais allons plus loin, n'ayons pas peur !

    En fait je ne vois pas ça comme une contrainte, c'est plus une conséquence d'une certaine manière d'organiser les dépendances.

    MAT.

  4. #4
    screetch
    Invité(e)
    Par défaut
    cette loi me parait difficile a mettre en place en C++ et donc pas pragmatique du tout.
    je prefere en un sens les classes "protected" et "private" de certains langages qui font que certaines classes sont accessibles seulement a l'implémentation du meme module mais pas au dela, forcant ainsi cette loi a etre appliquée sous peine d'erreur de compilation.

    je ne vois pas de probleme particulier a parler a deux entités que je connais, je vois un probleme lorsque depuis une entité que je connais, je choppe une entité que je ne suis pas sensé connaitre, j'appelle des methodes dessus.

  5. #5
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Pensez-vous respecter cette loi ? La trouvez-vous trop contraignante ? Quand pensez-vous devoir la respecter et quand la violer ? Bref, quel est votre sentiment ?
    Personnellement, je trouve cette loi "naturelle". C'est-à-dire qu'elle s'impose d'elle même en douceur lorsqu'on a le bon niveau d'abstraction. Pour un problème donné, il y a toujours au moins une modélisation / implémentation qui va nous donner ce résultat : couplage minimal et réutilisabilité maximale.
    Cependant, en pratique, on tombe très rarement sur la bonne modélisation du premier coup. Et souvent, on s'en rend compte. On est obligé de connaitre trop de détails. C'est plus qu'une loi qu'on viole, ce sont de gros problèmes qui vont pas tarder à pointer leur nez.
    En ce qui me concerne, je n'hésite pas à reprendre mon code, et réfléchir à une nouvelle modélisation, mieux adaptée. Mais ceci n'est possible qu'avec du temps. Dans une équipe avec des délais serrés, je met ma main à couper que la violation de cette loi est secondaire. Dans un projet plus long terme et où l'évolution sera importante, son respect est primordial.

  6. #6
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    :o ; On peux aussi se mettre un doigt dans le *** et chanter la reine Margot en programmant....

    Quand on programme en c++, il y a globalement deux objectifs : l'efficacité et la clarté.

    En reprenant l'exemple de deloget; oui il est possible de faire une combineinthesamedirection(); qui, si on veut être performant, sera un vieille inline... mais bonjour la clarté ! On va se retrouver à faire 40 fonctions inlines, qui pourriront une potentiel doc, juste pour respecter cette loi...

    --> Moins de clarté, pas plus de perf = Poubelle.

    Déclarer un getters en const Type& veut bien dire ce que ça veut dire : On retourne un objet dont on pourra se servir => conférer à cette doc. Ca s'appelle du partitionnement, de la décentralisation en politique; de la sous-traitance en industrielle. (puis commencé à faire comme si y avait pas de sous-traitance, c'est malsain).

    Et puis avec la venue des rrefs dans C++0x, je la trouve vraiment contre productive (en tout cas en c++).

    Bon, après, c'est comme pour une bonne page internet. Il y a deux choses qui produise un manque de clarté : la profondeur et la largeur. Si cette loi pose un problème sur la largeur; il faut tâcher aussi de ne pas s'embourber dans du :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     param.getter().getter().getter().getter().method();
    Seulement, y a pas vraiment de règle pour ça. Demeter est certes un pattern intéressant, mais pas une loi !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    J'ai vraiment l'impression que ça peut mener à du code ravioli...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par 3DArchi
    Pensez-vous respecter cette loi ? La trouvez-vous trop contraignante ? Quand pensez-vous devoir la respecter et quand la violer ? Bref, quel est votre sentiment ?
    En ce moment, j'ai bien peur de lui faire subir les pires outrages.

    Et justement, j'aimerais vous présenter le cas sur lequel je travaille actuellement, car il illustre bien, à mon sens, les difficultés que l'on rencontre parfois à appliquer la loi de Demeter.

    Le scénario :

    Nous avons une architecture client/serveur. Le serveur envoie une liste de tâche à effectuer ("d'action") sous la forme d'un fichier XML, que le client lit et interprète. Nous n'avons pas eu le choix de la techno (XML) ni de la structure du fichier, car nous respectons simplement une norme X.

    L'XML ressemble à peu près à l'arbre suivant (les ... indiquent la présence de champ supplémentaire supprimé ici pour simplifier)
    Code xml : 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
    18
    19
    20
    21
    22
    23
     
    <Message>
       <MessageHeader>
          <Identification>
             ...
          <Identification>
       </MessageHeader>
       <MessageBody>
          <Data>
             <Actions>
                <Action>
                   <Number> 0 </Number>
                   ....
                </Action>
                <Action>
                   <Number> 1 </Number>
                   ....
               </Action>
             </Actions>
          </Data>
          ....
       </MessageBody>
    </Message>

    J'admet ne pas avoir réfléchi en profondeur au problème et le temps manquant, j'ai simplement crée un ensemble de classes mirroirs du XML :

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    struct Message
    {
       MessageHeader header;
       MessageBody body;
    };
     
    struct MessageHeader
    {
       Identification id;
       ...
    };
     
    struct MessageBody
    {
        Data data;
        ....
    };
     
    struct Data
    {
        std::vector<Action> actions;
    }
     
     
    struct Action
    {
       int number;
       ...
    };
    Vi, que des structs, tout en public .
    Pour éviter un boxon infame, j'ai quand même encapsulé l'objet racine, Message, dans une classe capsule, unique, non copiable, la seule autorisée à manipuler les données issus de l'XML.

    Par contre, cela veut dire qu'à l'interieur de cette classe capsule, j'ai fréquement du code comme ceci :
    (Attention, démétériste convaincu, fermez les yeux)

    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
    18
    19
    20
     
    class Capsule
    {
    ....
    private:
        Message message_;
    }
     
    void Capsule::ExecuteAction()
    {
       std::vector<Action>& actions = message_.body.data.actions; 
       for(int i = 0 ; i < actions.size() ; i++)
      {
          ...
          Truc& t = actions[i].chose.machin.truc;
          if(t.number == ...)
          ...
     
      } 
    }
    Demeter outragée ! Demeter brisée ! Demeter martyrisée !

    Cependant, j'ai jeté un coup d'oeil au code de la personne ayant écrit la partie serveur (en java), qui a beaucoup plus d'expérience professionel et qui a eu plus de temps aussi : son approche est finalement assez similaire, il a même poussé le vice en utilisant un outil générant automatiquement les classes mirroirs du XML à partir d'une feuille XSLT. (et qui génère aussi des getter partout, java oblige ). Son code est donc plein à craquer de getMessage().getBody().getData().getActions().getTruc()...

    Qu'en pensez-vous ? Quel serait selon vous un meilleur design ? Est-ce que la Loi de Demeter est applicable à ce cas de figure ?

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Emmanuel Deloget
    Le premier cas est celui des structure triviales (par exemple les types POD en C++) qui ne définissent que des membres publics. Il est évident qu'imposer l'utilisation de la Loi de Demeter sur des structures aussi simples est un non-sens - même si on se rends compte que c'est dans certains cas préférable.
    A relativiser car dépend des détails de ton projet :
    J'ai l'impression que tes structures n'ont que pour but de séparer les différents éléments constituants d'un message mais qu'elles n'ont pas de sens en tant que telles. A partir de là, on peut dire que ton message aurait pu être défini 'à plat' comme suit :
    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
    18
     
    struct Message
    {
       int header_it;
       std::string header_prop_1;
       // ...
       double body_prop_1;
       std::string body_prop_2;
      // ...
       std::vector<Action> body_actions;
    };
     
     
    struct Action
    {
       int number;
       ...
    };
    Du peu que tu décris et du nom des éléments, il semblerait que seul Action puisse être plus qu'un regroupement d'éléments pour être un 'vrai' type avec des membres propres et - pour reprendre le vocabulaire - un protocole défini. Et c'est sur les invocations de type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    actions[i].chose.machin.truc
    qu'il faudrait réfléchir pour avoir la bonne abstraction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    actions[i].cuisine_moi_un_truc.

  10. #10
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par 3DArchi
    J'ai l'impression que tes structures n'ont que pour but de séparer les différents éléments constituants d'un message mais qu'elles n'ont pas de sens en tant que telles.
    Exactement. C'est le point sur lequel j'ai beaucoup hésité au début. Faire un miroir parfait de l'XML sans se poser de question, ce qui implique de créer pas mal de petites stuctures et de briser Demeter, ou de faire moins de structure, mais à plat, en essayant d'extraire des unités logiques.

    Au final, j'ai choisi la solution "miroir" car l'arbre réel est plus complexe que l'extrait montré et j'avais un peu peur que la personne qui reprendra le code soit complètement perdu si je commence à mettre certains éléments à plat, d'autres pas, selon une logique forcement logique pour celui qui a écrit le code, car il a une vue d'ensemble du projet, mais beacoup moins pour un simple lecteur.

    Puis bon, il y avait moins à réfléchir, j'avoue.

  11. #11
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    Comme je l'ai dit dans ma réponse initiale, je trouve cette loi très bien.

    Sauf que, en pratique, ça donne souvent l'obligation de créer des wrappers qui vont diviser l'indirection.

    L'exmple de Deloget est parlant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    edgeGroups.add(edge.getDirection().combine(edges));  // incorrect
    edgeGroups.add(combine(edge.getDirection(), edges)); // incorrect
    edgeGroups.add(edge.combineInSameDirection(edges));  // CORRECT
    On a du créer une méthode combineInSameDirection pour respecter la loi de Demeter.

    Si on veut combiner dans une autre direction que celui de edge, il faut utiliser la 2è méthode, qui ne respecte pas la loi car on récupère une direction via edge, et qu'on l'utilise.

    Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( otherEdge.getDirection(), edges ) );
    Qui ne respecte donc pas la loi.

    Ce qu'on doit faire, alors c'est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( otherEdge, edges ) );
    Et c'est edge qui doit récupérer la direction de otherEdge. En somme, pour respecter la loi de Demeter, on a déplacer du code.

    C'est très bien et facile à appliquer quand on a une association ternaire, mais que se passe-t-il à partir du moment où on a une association comprenant plus d'entités ?

    En essayant d'appliquer la loi à la lettre, on va se retrouver à créer des responsabilités là où il n'est pas nécessaire d'en avoir.

    Imaginons par exemple que edge est dépendant de Direction, comme dans l'exemple de Deloget.

    On va créer une classe fictive, Foo, qui dépendra également de Direction, dépendra non dans le sens hiérarchique, mais qui possède une instance de Direction.

    Et c'est là que le bas blesse:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    edgeGroups.add( edge.combine( Foo, edges ) );
    edge ne connait pas Foo.

    On peut "bypass" le problème en créant une interface d'abstraction pour tous les objets qui possèdent une instance Direction.

    Résultat: on a de la redondance de code car l'implémentation de l'interface va se retrouver dans toutes les classes qui utilisent Direction.

    Il est hors de question d'avoir un héritage de Direction pour traiter le problème de redondance, vu que notre classe n'est PAS une direction, et ne doit pas être traité comme tel.

    Ceci n'est que ma pensée, et je n'ai pas été chercher trop loin, mais il me semble avoir été confronté à ce genre de problèmes lorsque je m'efforçais de respecter la loi de Demeter.

    Pour moi, la redondance de code c'est pire que le non respect d'une loi dans certains cas.

    Après, bien sûr, l'appliquer à chaque fois que c'est possible, c'est très très bien, chose d'ailleurs que je m'efforce de faire. Il est hors de question de laisser tomber cette loi qui apporte bien des choses pour la maintenance et pour l'évolution.
    Je comprends le point. Cependant, d'après mon expérience,

    * peu de classes dépendent d'une classe importante ; si c'est le cas, alors il y a probablement un problème de non respect du SRP dans la classe utilisée.
    * il est très rare de voire deux classes différentes avoir besoin du même traitement. Si le traitement est identique, il convient de se poser la question "pourquoi". Il peut y avoir de nombreuses réponses à cette question. Une fois que toutes les bonnes réponses à cette question ont été trouvée, la redondance de code doit être quasiment nulle. Bien sûr, dans la pratique, on ne peut éviter une certaine redondance, ne serait-ce que pour des problèmes de performance. Cette limitation n'est pas intrinsèque à la loi de Demeter, mais touche tous les langages objet ou orienté objet.

    Je dois dire que j'applique avec un certain succès la loi de Demeter aux projets sur lesquels je travaille. Il m'arrive de ne pas l'appliquer, et je m'en mord les doigts de manière quasiment systématique. En fait, je soupçonne la loi d'être plus qu'une loi de style (telle qu'elle a été imaginée à la base), et de n'être en fait qu'une représentation simplifiée de ce que j'appelle le principe d'encapsulation (qui n'est pas un des 5 principes fondateurs de l'architecture orientée objet, mais que j'ai choisi de nommer "principe" quand même).

    A propos de ton exemple Foo :

    Tu veux pouvoir travailler avec la direction stockée dans un objet de type Foo, un groupe d'Edge et un Edge qui servira de source. Le tout sans être obligé d'avoir une méthode de Edge qui connaisse le type d'objet Foo, afin de limiter les responsabilités. C'est louable. C'est même plutôt une bonne idée, à laquelle mon exemple simpliste ne peut pas répondre. Toutefois, ça ne montre que la limite de l'exemple que j'ai choisi - qui a pour but de montrer simplement le mécanisme mis en oeuvre pour respecter la loi de Demeter lorsqu'on écrit du code. Si j'ai bien compris ton exemple, je suis entièrement d'accord avec toi : mon exemple ne supportera que très difficilement ce que tu souhaite faire.

    Cependant, il y a plusieurs façon d'écrire les choses. Il existe nécessairement une façon de faire qui résout le problème (et non, ce n'est pas à 4h30 du matin que je vais la trouver) tout en respectant la loi de Demeter. Tout comme il existe forcément une limitation à cette façon de faire. C'est le jeu : no silver bullet...
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  12. #12
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Exactement. C'est le point sur lequel j'ai beaucoup hésité au début. Faire un miroir parfait de l'XML sans se poser de question, ce qui implique de créer pas mal de petites stuctures et de briser Demeter, ou de faire moins de structure, mais à plat, en essayant d'extraire des unités logiques.

    Au final, j'ai choisi la solution "miroir" car l'arbre réel est plus complexe que l'extrait montré et j'avais un peu peur que la personne qui reprendra le code soit complètement perdu si je commence à mettre certains éléments à plat, d'autres pas, selon une logique forcement logique pour celui qui a écrit le code, car il a une vue d'ensemble du projet, mais beacoup moins pour un simple lecteur.

    Puis bon, il y avait moins à réfléchir, j'avoue.
    Une fois que tu a les objets de base (tes structures), rien ne t'empêche d'ajouter les méthodes de traitement (c'est à dire ni des getters ni des setters) à ces classes / structures.

    Et le code java ou C# qu'on voit régulièrement ici et là me pique les yeux
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  13. #13
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Lavock Voir le message
    :o ; On peux aussi se mettre un doigt dans le *** et chanter la reine Margot en programmant....
    Là, tes collègues risquent de dire à ton chef que tu les perturbe un peu pendant leur travail. Mais c'est à tenter...

    Citation Envoyé par Lavock Voir le message
    Quand on programme en c++, il y a globalement deux objectifs : l'efficacité et la clarté.
    Voui. Mais dison plutôt : la clarté et l'efficacité.

    Citation Envoyé par Lavock Voir le message
    En reprenant l'exemple de deloget; oui il est possible de faire une combineinthesamedirection(); qui, si on veut être performant, sera un vieille inline... mais bonjour la clarté ! On va se retrouver à faire 40 fonctions inlines, qui pourriront une potentiel doc, juste pour respecter cette loi...

    --> Moins de clarté, pas plus de perf = Poubelle.
    Pas d'accord. La clarté dépends uniquement du bon choix des noms de méthode. Une méthode correctement nommé est claire. Un identifiant qui fait entre 5 et 25 caractères est largement lisible par tout programmeur qui se respecte.

    Ensuite : pas d'accord non plus. Non, on ne va pas se trouver à faire 40 inline - ça n'aurait pas de sens. Si on fait 40 inline dans une classe, alors il y a un vrai problème de non respect du SRP. Donc on ne va pas pourrir les docs, qui ne sont pas potentielles d'ailleurs, mais contractuellement exigée par la plupart des clients sensés.

    Donc au final : pas d'accord avec la conclusion. Ma conclusion est "plus de clarté, pas plus de perf -> on garde".

    Citation Envoyé par Lavock Voir le message
    Déclarer un getters en const Type& veut bien dire ce que ça veut dire : On retourne un objet dont on pourra se servir => conférer à cette doc. Ca s'appelle du partitionnement, de la décentralisation en politique; de la sous-traitance en industrielle. (puis commencé à faire comme si y avait pas de sous-traitance, c'est malsain).

    Et puis avec la venue des rrefs dans C++0x, je la trouve vraiment contre productive (en tout cas en c++).
    Je vois pas trop l'impact des rrefs la dedans.

    Citation Envoyé par Lavock Voir le message
    Bon, après, c'est comme pour une bonne page internet. Il y a deux choses qui produise un manque de clarté : la profondeur et la largeur. Si cette loi pose un problème sur la largeur; il faut tâcher aussi de ne pas s'embourber dans du :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     param.getter().getter().getter().getter().method();
    Seulement, y a pas vraiment de règle pour ça. Demeter est certes un pattern intéressant, mais pas une loi !
    C'est une loi de style. La taxonomie des loi/principes/patterns/... n'impose pas qu'une loi de style doit être nécessairement suivie. Chacun voit midi à sa porte.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  14. #14
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Là, tes collègues risquent de dire à ton chef que tu les perturbe un peu pendant leur travail. Mais c'est à tenter...
    Désolé, j'adore François Pérusse :p !

    Citation Envoyé par Emmanuel Deloget Voir le message
    Voui. Mais dison plutôt : la clarté et l'efficacité.
    Si tu veux, mais à mon avis, ça dépend surtout du niveau d'abstraction.

    Citation Envoyé par Emmanuel Deloget Voir le message
    Pas d'accord. La clarté dépends uniquement du bon choix des noms de méthode. Une méthode correctement nommé est claire. Un identifiant qui fait entre 5 et 25 caractères est largement lisible par tout programmeur qui se respecte.
    Mes cours (oui parce que je suis encore étudiant) d'ergonomie disent le contraire. C'est une question de mémorisation et de 7 + ou - 2 éléments. Je t'encourage à lire n'importe qu'elle didactique de psychologie cognitive (Et je te conseils de regarder vers Sciences Humaines pour approfondir).

    Citation Envoyé par Emmanuel Deloget Voir le message
    Ensuite : pas d'accord non plus. Non, on ne va pas se trouver à faire 40 inline - ça n'aurait pas de sens. Si on fait 40 inline dans une classe, alors il y a un vrai problème de non respect du SRP.
    C'est exagéré certes... Bon, je ne maîtrise pas trop le SRP, mais globalement, cela veux bien dire que tu ne dois pas avoir plusieurs raisons pour changer le code de ta classe, n'est ce pas ?
    J'ai l'impression que c'est là que cela se contredit un peu. En gros, le SRP dit "partitionnez les classes"; mais la loi de Demeter dit "faites comme si rien n'était partitionné"... Ton argument me laisse à vrai dire perplexe; et j'aimerais bien que tu le développes, s'il te plaît !

    Citation Envoyé par Emmanuel Deloget Voir le message
    Donc au final : pas d'accord avec la conclusion. Ma conclusion est "plus de clarté, pas plus de perf -> on garde".
    Effectivement, mes propos n'étaient pas mesurés. Je dirais que je le garde partiellement à vrai dire. (---> Excusez-moi, j'étais de mauvaise humeur )

    Citation Envoyé par Emmanuel Deloget Voir le message
    Je vois pas trop l'impact des rrefs la dedans.
    C'est pas trop le sujet, mais un des enjeux de cette loi et un meilleur maintien de l'encapsulation. Retourner un Type& signifie clairement que ce type est une donnée membre (ou alors vous avez de gros problème de fuite). Retourner un Type risque d'être trop couteux. Par contre, retourner un Type&& n'est pas couteux, et ne veux rien dire quant à l'implémentation!


    Citation Envoyé par Emmanuel Deloget Voir le message
    C'est une loi de style. La taxonomie des loi/principes/patterns/... n'impose pas qu'une loi de style doit être nécessairement suivie. Chacun voit midi à sa porte.
    Absolument d'accord; mais dites ça au magnat qui-ont-lu-que ou qu'on-leur-a-dit-que; et qui, même s'il ne savent pas programmer, savent ce qu'il y a de mieux ! Le principale reproche que je fais à ces exposés, c'est que généralement, il n'est pas écrit en gros ATTENTION RESERVE A UN LECTORAT AVERTI ou autres messages dissuasifs!
    Bon, en même temps, je suppose qu'on a pas à reprocher à l'auteur d'une loi/principe/... d'être lu par des gens qui devraient s'abstenir :'( !

    PS : Non, en ce moment, personne ne m'impose de principe quel qu'il soit, mais malheureusement cela m'est déjà arrivé (et pas qu'à moi je suppose).
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  15. #15
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Mes cours (oui parce que je suis encore étudiant) d'ergonomie disent le contraire. C'est une question de mémorisation et de 7 + ou - 2 éléments. Je t'encourage à lire n'importe qu'elle didactique de psychologie cognitive (Et je te conseils de regarder vers Sciences Humaines pour approfondir).
    meme si c'est vrai, élément ne veut pas dire caractère. élément est ici soit un mot, soit un paramètre.

    c'est pourquoi fonctionQuiFaitQuelqueChoseEtMemePlusEncore( Type1 paramètre1, Type2 paramètre2, ... Type72 paramètre72) est imbuvable.

    mais "fonctionCompliquéeAvecComplications(Type1 paramètre1)" est parfaitement lisible. 7 lettres pour une fonction c'est plus idiot qu'ergonomique.

  16. #16
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par screetch Voir le message
    meme si c'est vrai, élément ne veut pas dire caractère. élément est ici soit un mot, soit un paramètre.

    c'est pourquoi fonctionQuiFaitQuelqueChoseEtMemePlusEncore( Type1 paramètre1, Type2 paramètre2, ... Type72 paramètre72) est imbuvable.

    mais "fonctionCompliquéeAvecComplications(Type1 paramètre1)" est parfaitement lisible. 7 lettres pour une fonction c'est plus idiot qu'ergonomique.
    => Hum, j'ai peut-être manqué de clarté; mais c'est au niveau du nombre de méthode accessible depuis une même classe, pas de son nommage.

    Et oui, la notion élément est difficilement définissable, mais ce n'est pas a nous pauvres informaticien de clairement définir cette notion.
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Je trouve le respect de cette loi aussi indispensable que le respect du LSP...

    Il n'y a qu'à voir les questions du forum pour se rendre compte que, dans un très grosse majorité des cas (tout ce qui ne concerne pas uniquement la syntaxe ou la "grammaire" du C++), le problème posé est, à la base, du à une mauvaise conception et au non respect de ces deux principes.

    Je suis sur que, si on fait une recherche sur ce forum, même limitée à trois mois, on retrouve, au départ de différents intervenants, surement plusieurs dizaines de références à ces deux lois, ce qui montre que leur respect est presque aussi primordial que le fait de respirer

    My 2 cents
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Salut,

    Personnellement je ne la trouve pas assez sévère !

    En général je me retrouve avec deux sortes de code différents : le code bas niveau qui est du code générique pour mettre en place les briques de base, et le code de plus haut niveau très orienté objet qui assemble ces briques.
    Au fil du temps je me suis aperçu que le code de haut niveau finit par n'avoir presque que des méthodes qui retournent void, avec parfois un bool par-ci par-là, mais en tous cas aucun getter (et très peu de setters).

    Bref Demeter oui bien sûr, mais allons plus loin, n'ayons pas peur !

    En fait je ne vois pas ça comme une contrainte, c'est plus une conséquence d'une certaine manière d'organiser les dépendances.

    MAT.
    voir, éventuellement, un size_t, lorsque la classe manipule une collection d'objet.
    Citation Envoyé par Lavock Voir le message
    => Hum, j'ai peut-être manqué de clarté; mais c'est au niveau du nombre de méthode accessible depuis une même classe, pas de son nommage.

    Et oui, la notion élément est difficilement définissable, mais ce n'est pas a nous pauvres informaticien de clairement définir cette notion.
    A vrai dire, si tu viens à décider de travailler avec des getters / setters, tu en arrivera, au final, à un nombre de méthodes équivalent à deux fois le nombre d'éléments qu'une classe utilise.

    Lorsque tu décide de respecterla loi demeter, tu peux, effectivement, en arriver à un maximum de N! fonctions membres (ou N est le nombre d'éléments que la classe utilise).

    Cependant, seule une petite partie de ces fonctions membres prend réellement un sens pour la classe que tu es occupé à créer, et il n'est pas rare (une méthode pouvant utiliser plusieurs éléments de manière simultanée) que tu en arrive même à un nombre de fonctions membre quasi inférieur au nombre de variables membres.

    Maintenant, c'est souvent lié au problème évoqué par 3DArchi et par Arzar en ce qui concerne les objets POD...

    Mais, rien ne t'empêche, non plus (et j'ai l'impression qu'on ne le fait pas assez souvent) de créer une structure imbriquée et privée représentant les données réellement manipulées au sein d'une clase
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  19. #19
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par koala01 Voir le message
    A vrai dire, si tu viens à décider de travailler avec des getters / setters, tu en arrivera, au final, à un nombre de méthodes équivalent à deux fois le nombre d'éléments qu'une classe utilise.

    Lorsque tu décide de respecterla loi demeter, tu peux, effectivement, en arriver à un maximum de N! fonctions membres (ou N est le nombre d'éléments que la classe utilise).
    C'est surtout une question d'organisation. Si jamais, pour quelque raison que ce soit; ton interface autorise publiquement à faire 20 actions, déjà il te faut nécessairement les séparer (SRP) dans différentes classes. Donc ensuite, peut importe la méthode, tu imbriques ces classes.

    La, si on respecte Demeter, il faudrait que tout soit à plat. Mais ce que veux une bonne ergonomie, c'est que l'on organise ces fonctions en arbre; getters ou pas, on s'en fout. Du coup, au final, on aura peut-être 3 ou 4 méthodes supplémetaires en tout, mais elle ne seront que les noeuds d'un arbre.

    Evidemment, on peur faire ça par le nommage... M'enfin je vois pas ce que, au niveau clarté ou perf, cela apporte. Au contraire, trop de verbosité, cela file des boutons (et démultiplie les possibilités de fautes de frappe) !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  20. #20
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2006
    Messages : 51
    Points : 64
    Points
    64
    Par défaut
    Eh bien, il ne faut pas oublier le bon sens!

    La loi de Demeter est très bien, elle permet de se poser les bonnes questions sur les relations entre les objets. Typiquement si on prends les principes énoncés par Oncle Bob, on pourrait éventuellement s'éloigner de la loi de Demeter pour les classes qui sont assez cohesives (normalement dans le même package). Evidement il en faut pas non plus se laisser aller.

    Personnellement (et je peux avoir tort la dessus!) j'essaye de respecter au maximum la loi, mais quand je suis "contraint" de la casser je me limite à deux niveaux de profondeur, au delà le code devient bien trop couplé.

    Je pense que sémantiquement il faudrait plutôt l'appeler le Principe de Demeter; dans le sens que ce principe n'est pas obligatoire, mais trop s'en éloigner est mauvais pour la qualité et la maintenabilité du code.

Discussions similaires

  1. Que pensez-vous des générateurs de doc PHP ?
    Par Nonothehobbit dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 64
    Dernier message: 10/07/2007, 10h17
  2. Que pensez vous de filemaker
    Par thpopeye dans le forum Autres SGBD
    Réponses: 4
    Dernier message: 14/06/2007, 15h20
  3. Que pensez vous du nouveau kernel 2.6 ?
    Par GLDavid dans le forum Administration système
    Réponses: 58
    Dernier message: 02/08/2004, 15h45
  4. [Débat] Que pensez-vous des langages à typage dynamique?
    Par Eusebius dans le forum Langages de programmation
    Réponses: 14
    Dernier message: 16/06/2004, 12h12
  5. Que pensez vous du mariage ASP Flash?
    Par tyma dans le forum Flash
    Réponses: 4
    Dernier message: 09/07/2003, 15h00

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