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. #121
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 11
    Points : 0
    Points
    0
    Par défaut
    Citation Envoyé par koala01 Voir le message
    La plupart des bibliothèques (C++, s'entend) de GUI sont particulièrement mal foutues et témoignent, au mieux (mais c'est logique quand on voit leur histoire et l'époque à laquelle leur développement a commencé) d'une mauvaise compréhension du paradigme orienté objet, et, dans quasiment tous les cas, certains principes SOLID (dont le LSP en premier) sont purement et simplement jetés aux orties.

    Je ne remets ici absolument pas en question la qualité du travail effectué pour fournir ces bibliothèques, et j'apprécie énormément certaines d'entre-elles. Mais, de manière générale, la conception d'une bibliothèque d'IHM n'est vraiment pas le meilleur exemple à prendre
    J'ai bien compris que tu ne doutais pas de la qualité du travail effectué par ces équipes, mais de celle du résultat obtenu.

    Citation Envoyé par koala01 Voir le message
    Ben, dans ton article, la classe Agent a surtout vocation... d'exposer tous les services proposés par l'ensemble de ses composants.

    Or, ta classe Agent devrait avoir vocation à ... utiliser en interne les services proposés par les composants, de manière à ce qu'elle puisse se limiter à exposer ... que les seuls services que l'on est en droit d'attendre de sa part.
    Ben, oui et non!

    Tu pars (enfin, comme tu reste très vague sur le sujet, on va partir d'un a priori favorable )sur une approche orientée service pour les composants de ta classe Agent, mais, en voulant absolument faire en sorte que ta classe agent "réplique" tous les services de tous les composants qu'elle utilise, tu agis littéralement de la même manière que si tu suivais une logique orientée donnée. La seule différence est que tu pars du principe d'exposer les services fournis par les composant de ta classe Agent au lieu de donner accès à ces composants.

    Mais, au final, cela revient au même : tu penses à ta classe Agent en termes des données qu'elle manipule et non en termes des services qu'elle doit être en mesure de rendre à son utilisateur

    Au moins, un service affiche() ne nécessiterait pas que l'utilisateur sache exactement de quoi est composée ta classe Agent... Cette fonction utiliserait tous les composants de la classe Agent dont elle a besoin pour rendre le service attendu. Et respecterait parfaitement la loi de Déméter.

    Mais on est très loin de ce que tu présente dans ton article
    Au contraire : les SMA sont la cible parfaite pour mettre correctement Déméter en application!!!

    Car, tout ce que l'on attend de la part des agent est... de réagir (correctement) aux ordres que l'on est susceptibles de leur donner. Et donc, les seuls services "dignes" d'être exposés au niveau des agents sont... les ordres auxquels ils doivent pouvoir réagir et éventuellement quelques "aides à la décision" permettant à l'utilisateur de choisir de donner (ou non) un ordre particulier. Et l'utilisateur d'un agent particulier n'a ABSOLUMENT PAS A SAVOIR DE QUOI L'AGENT QU'IL UTILISE EST COMPOSE;

    Cela n'a rien à voir !!! A partir du moment où tu considère que ton agent doit exposer la (quasi) totalité des services fournis par ses composants, tu fais purement et simplement fausse route : l'agent n'a à exposer que les services qu'on attend de sa part!

    Certains de ces services peuvent éventuellement correspondre à des services définis "tels quels" dans un composant donné de ton agent, mais cela reste l'exception! autrement, nous ne nous serions pas "cassé le cul" à regrouper différents composants au niveau de la classe Agent : nous aurions simplement utilisé ces composants séparément et "basta".

    Si on a décidé de regrouper plusieurs composants au niveau de la classe Agent, ce n'est que parce que l'on s'est bel et bien rendu compte que les différents composants devaient être utilisés conjointement à certaines occasions. Et les services exposés par ta classe Agent ne correspondent en réalité qu'à ... ces "occasions particulières" dans lesquelles les différents composants doivent être utilisés conjointement

    koala01 (et Bousk aussi, d'après son dernier post), tu sembles bloquer de manière récurrente sur deux aspects :
    - tu n'acceptes pas l'idée que les services offerts par les composantes de Agent doivent tous être répliqués dans Agent elle-même. La raison est que ces composantes sont des types du domaine métier et connus du client par ailleurs. Je l'ai bien précisé dans l'article. Et lorsqu'un type est connu du client, on doit considérer que chaque service offert par ce type (comprendre chaque service de son interface publique) peut être utilisé par ce client. C'est aussi simple que cela. Maintenant, le point que tu pourrais contester (tu l'as fait) est la légitimité du fait que les types de ces composantes soient utilisés par le client par ailleurs. Seulement, c'est une hypothèse ! Une hypothèse au sens de la logique traditionnelle. C'est mon exemple, donc j'en fixe les données, c'est normal. Si tu refuses l'hypothèse de travail, tu passes à autre chose. Mais si tu veux argumenter sur l'exemple principal de mon article, il faut en accepter les hypothèses.
    - tu reproches à la conception alternative que je propose, le fait qu'elle expose sa structure interne au client. Mais elle ne l'expose pas, comme je l'ai expliqué dans le (*) de mon article.


    Mais peut-être qu'en inversant le sens de ma démonstration, ces deux points te sembleront plus clairs :

    Situation 1 :
    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
     
    class Agent
    {
    public:
       string nom() const { return m_nom; }
       string affiche() const;
     
       void demarre() { m_comportement.demarre(); }
       void arrete() { m_comportement.arrete(); }
       string descriptionComportement() const { return m_comportement.description(); }
     
       bool connait(const Fait & fait) const { return m_savoir.connait(fait); }
       bool peutDeduire(const Fait & fait) const { return m_savoir.peutDeduire(fait); }
     
    private:
       Comportement m_comportement;
       Savoir m_savoir;
       string m_nom;
    };
    ---- code client ----
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Agent Luc;
    Luc.demarre();
    Luc.affiche();
    gereObstacles(Luc);           // n'utilise que Agent::arrete
    afficheConnaissances(Luc); // n'utilise que Agent::connait et Agent::peutDeduire
    Dans la situation 1, la classe Agent offre un accès direct à l'ensemble des services nécessaires pour gérer les Agents de ma simulation. Ca me parait pas mal, sauf que, à y regarder de plus près, on voit que l'ISP (http://www.tomdalling.com/blog/softw...ion-principle/) n'est pas respecté. On voit en effet que les services demarre, arrete et descriptionComportement semblent toutes relatives aux actions de l'agent, que connait et peutDeduire semblent relatives aux connaissances de l'Agent, et que ces deux groupes cohérents semblent indépendants les uns des autres. Le diagnostic est confirmé quand on réalise que les fonctions gereObstacles et afficheConnaissances n'utilisent chacune qu'un des groupes de services.

    La solution typique pour résoudre se problème est de créer autant d'interfaces spécifiques que de groupes identifiés, de faire hériter Agent de ces interfaces spécifiques, puis de modifier la signature des fonctions gereObstacles et afficheConnaissances de manière à ce qu'elles ne manipulent plus que ces interfaces spécifiques.

    Dans le cas présent cependant, je remarque que l'interface publique de ces interfaces spécifiques à créer correspond exactement à celle des types Comportement et Savoir utilisés pour implémenter leurs services (modulo quelques raccourcis de noms). Comme ces types sont connus et utilisés par ailleurs par le client, il est inutile à ce stade de créer des interfaces mimant ces types publiques. J'ajoute donc simplement des accesseurs aux composantes concernées de classe Agent, j'ajoute les indirections qu'il faut dans le code client, je renomme certains appels, et je modifie la signature des fonctions gereObstacles et afficheConnaissances de manière à ce qu'elles ne manipulent plus que les abstractions spécifiques.

    Ce qui nous donne la situation 2 :
    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
     
    class Agent
    {
    public:
       string nom() const { return m_nom; }
       string affiche() const;
     
       Comportement & getComportement() { return m_comportement; } // de même pour const
       Savoir & getSavoir() { return m_savoir; } // de même pour const
     
       void demarre() { m_comportement.demarre(); }
       void arrete() { m_comportement.arrete(); }
       string descriptionComportement() const { return m_comportement.description(); }
     
       bool connait(const Fait & fait) const { return m_savoir.connait(fait); }
       bool peutDeduire(const Fait & fait) const { return m_savoir.peutDeduire(fait); }
     
    private:
       Comportement m_comportement;
       Savoir m_savoir;
       string m_nom;
    };
    ---- code client ----
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Agent Luc;
    Luc.getComportement().demarre();
    Luc.affiche();
    gereObstacles(Luc.getComportement());     // n'utilise que Agent::arrete
    afficheConnaissances(Luc.getSavoir());       // n'utilise que Agent::connait et Agent::peutDeduire
    Dans cette situation 2,
    - nous avons adressé le problème de l'ISP, et donc nous en tirons les avantages. Par rapport à la solution habituelle des interfaces spécifiques, nous avons évité la création de ces types supplémentaires, et nous avons introduit une indirection dans l'appel à certains services, permettant parfois un nommage plus clair.
    - nous avons conservé l'indépendance du client vis-à-vis de la structure interne de la classe Agent. En effet, les indirections ne marquent qu'une structuration de l'interface publique de Agent. Du point de vue du client, les nouveaux accesseurs permettent d'accéder à des composantes de l'interface publique. Celles-ci correspondent pour l'instant aux composantes internes de Agent, mais c'est un détail technique. Si le besoin se fait sentir de modifier la structure interne de Agent (par exemple en fusionnant deux composantes internes) et qu'on ne souhaite pas modifier le code client, il suffira alors de créer les interfaces spécifiques évoquées plus haut, en les implémentant de manière adéquate dans Agent. Remarquons qu'il est peu probable qu'une restructuration interne se produise, puisque la structure interne actuelle reflète la structure de l'interface publique de Agent, laquelle découle de l'ISP, lequel ne s'applique que quand on isole des groupes stables de services.


    Ma conclusion : la qualité logicielle a strictement augmenté en passant de la situation 1 à la situation 2.

    Dans l'exemple de mon article, la situation 1 correspond à l'"après Déméter", et la 2 à l'"avant Déméter".
    Il n'y a aucune différence, excepté le choix de quelques membres pour illustrer la démonstration.

  2. #122
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Par contre, tu perds la possibilité d'avoir un agent qui choisit son comportement parmi plusieurs, en fonction de ce qu'il estime être le besoin.
    Tu perds aussi la possibilité d'avoir un Agent qui implémente son propre comportement.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #123
    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 igor_ Voir le message
    koala01 (et Bousk aussi, d'après son dernier post), tu sembles bloquer de manière récurrente sur deux aspects :
    - tu n'acceptes pas l'idée que les services offerts par les composantes de Agent doivent tous être répliqués dans Agent elle-même. La raison est que ces composantes sont des types du domaine métier et connus du client par ailleurs. Je l'ai bien précisé dans l'article. Et lorsqu'un type est connu du client, on doit considérer que chaque service offert par ce type (comprendre chaque service de son interface publique) peut être utilisé par ce client. C'est aussi simple que cela. Maintenant, le point que tu pourrais contester (tu l'as fait) est la légitimité du fait que les types de ces composantes soient utilisés par le client par ailleurs. Seulement, c'est une hypothèse ! Une hypothèse au sens de la logique traditionnelle. C'est mon exemple, donc j'en fixe les données, c'est normal. Si tu refuses l'hypothèse de travail, tu passes à autre chose. Mais si tu veux argumenter sur l'exemple principal de mon article, il faut en accepter les hypothèses.
    Citation Envoyé par wikipedia
    Une hypothèse est une proposition ou une explication que l'on se contente d'énoncer sans prendre position sur son caractère véridique, c'est-à-dire sans l'affirmer ou la nier. Il s'agit donc d'une simple supposition, appartenant au domaine du possible ou du probable. Une fois énoncée, une hypothèse peut être étudiée, confrontée, utilisée, discutée ou traitée de toute autre façon jugée nécessaire, par exemple dans le cadre d'une démarche expérimentale.

    Une hypothèse destinée à être travaillée ou vérifiée est désignée par l'expression « hypothèse de travail » ; au contraire, une hypothèse utilisée sans intention de la vérifier (pour des raisons sentimentales, religieuses ou politiques par exemple) constitue un postulat. (source)
    Dans ton article, tu n'es pas occupé à émettre un postulat, tu émets une hypothèse de travail.

    La première chose à faire face à ce genre d'hypothèse est donc d'en prouver le bien-fondé au travers d'une démonstration (quitte à ne pas le faire dans ton article, soit).

    Le fait est que ton hypothèse de travail est fausse, autrement cela aurait été une thèse.

    A l'extrême limite, si tu avais dit que la classe utilisatrice expose un nombre de services correspondant à l'ensemble de toutes les combinaisons possibles que l'on peut obtenir en utilisant un ou plusieurs comportements des classes utilisées, j'aurais encore pu accepter, car c'est -- à peu près -- ce qu'il se passe effectivement. A ceci près :
    1. que certaines combinaisons sont redondantes ;
    2. que certaines combinaisons sont purement incohérentes par rapport au domaine traité (ex : si tu as un oeuf et un fouet électrique, tu les seules combinaisons possibles passent par le fait... de casser l'oeuf en tout premier lieu )
    3. que KISS et YAGNI t'inciteront de toutes façons à ne fournir que les services dont tu as effectivement besoin à un instant T

    Le (1) et le (2) limite de facto le nombre de services "exposables"; le 3 fait que si multiplication des services il y a, elle sera suffisamment étalée dans le temps pour que, en tant que développeur de la classe, tu n'aies pas à t'inquiéter de leur nombre.
    - tu reproches à la conception alternative que je propose, le fait qu'elle expose sa structure interne au client. Mais elle ne l'expose pas, comme je l'ai expliqué dans le (*) de mon article.
    Mais c'est tout comme, à partir du moment où tu tiens à exposer tous les services proposés par les données utilisées.

    Il n'y a aucune différence entre se dire
    Ma classe utilise trois donnée, je donne accès à ces trois données au travers d'une accesseur (et pire, au travers d'un mutateur)
    et se dire
    Ma classe utilise X données qui proposent Y services, j'expose donc tous les services propose donc les Z services correspondant à la somme de tous les services proposés par les données interne au niveau de ma classe
    car, au final, ce à quoi l'utilisateur de ta classe va utiliser c'est... les données internes.

    Mais bon, continuons...
    Situation 1 :
    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
     
    class Agent
    {
    public:
       string nom() const { return m_nom; }
       string affiche() const;
     
       void demarre() { m_comportement.demarre(); }
       void arrete() { m_comportement.arrete(); }
       string descriptionComportement() const { return m_comportement.description(); }
     
       bool connait(const Fait & fait) const { return m_savoir.connait(fait); }
       bool peutDeduire(const Fait & fait) const { return m_savoir.peutDeduire(fait); }
     
    private:
       Comportement m_comportement;
       Savoir m_savoir;
       string m_nom;
    };
    ---- code client ----
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Agent Luc;
    Luc.demarre();
    Luc.affiche();
    gereObstacles(Luc);           // n'utilise que Agent::arrete
    afficheConnaissances(Luc); // n'utilise que Agent::connait et Agent::peutDeduire
    Dans la situation 1, la classe Agent offre un accès direct à l'ensemble des services nécessaires pour gérer les Agents de ma simulation. Ca me parait pas mal, sauf que, à y regarder de plus près, on voit que l'ISP (http://www.tomdalling.com/blog/softw...ion-principle/) n'est pas respecté. On voit en effet que les services demarre, arrete et descriptionComportement semblent toutes relatives aux actions de l'agent, que connait et peutDeduire semblent relatives aux connaissances de l'Agent, et que ces deux groupes cohérents semblent indépendants les uns des autres. Le diagnostic est confirmé quand on réalise que les fonctions gereObstacles et afficheConnaissances n'utilisent chacune qu'un des groupes de services.
    Mais, le non respect de l'ISP, il vient de où à ton avis

    Cela va peut-être te surprendre, mais il ne vient que de ta décision aberrante, de ton ineptie (et je pèse mes mots) de vouloir exposer... tous les services proposés par les structures internes au niveau de ta classe utilisateur!

    En plus, a vouloir exposer les services proposés par tes structures internes, tu as raté une fantastique occasion d'appliquer le DIP et l'OCP en même temps.

    Et donc, forcément : à agir de la sorte, tu viens de jeter au moins trois principes essentiels de la programmation OO aux orties. Puis tu t'étonnes d'en arriver à la conclusion que Déméter ne sert à rien

    Allez, encore un petit effort, tu devrais pouvoir en profiter pour jeter également LSP et SRP aux orties, comme cela, le tableau sera complet

    Ne crois tu pas qu'il serait beaucoup plus sensé de revoir ton hypothèse de travail, d'appliquer SOLID (sans t'inquiéter de Déméter dans un premier temps) de manière scrupuleuse et voire, ensuite ce que cela donne au niveau de Déméter

    Je peux t'assurer que, en travaillant de la sorte, tu te rendra compte que Déméter est déjà respecté ... ou peu s'en faut!
    La solution typique pour résoudre se problème est de créer autant d'interfaces spécifiques que de groupes identifiés, de faire hériter Agent de ces interfaces spécifiques, puis de modifier la signature des fonctions gereObstacles et afficheConnaissances de manière à ce qu'elles ne manipulent plus que ces interfaces spécifiques.
    Il sera peut-être utile de créer des interfaces séparées, en effet... Il serait beaucoup plus utile de revoir ton hypothèse de travail
    Dans le cas présent cependant, je remarque que l'interface publique de ces interfaces spécifiques à créer correspond exactement à celle des types Comportement et Savoir utilisés pour implémenter leurs services (modulo quelques raccourcis de noms). Comme ces types sont connus et utilisés par ailleurs par le client, il est inutile à ce stade de créer des interfaces mimant ces types publiques. J'ajoute donc simplement des accesseurs aux composantes concernées de classe Agent, j'ajoute les indirections qu'il faut dans le code client, je renomme certains appels, et je modifie la signature des fonctions gereObstacles et afficheConnaissances de manière à ce qu'elles ne manipulent plus que les abstractions spécifiques.
    Parce que tu as décidé -- en dépit de tout bon sens -- de le faire comme cela!!!

    Admets que cette idée de vouloir exposer tous les services proposés par les données utilisée est une connerie monumentale, fais marche arrière à ce niveau là, et tu verras que toutes tes objections tomberont les unes après les autres!

    A la limite, ton article suit un raisonnement par l'absurde pour justement démontrer ce qu'il ne faut pas faire
    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

  4. #124
    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
    (désolé pour le double post, mais je viens de trouver un nouvel angle d'attaque!)

    Si tu veux bien, igor_, nous allons reprendre ton raisonnement depuis le début, cela t'aidera sans doute à comprendre "ou le bât blesse"

    Tu pars de l'hypothèse
    Ma classe utilisatrice doit exposer tous les services proposés par les données qu'elle utilise
    Soit, mais cela signifie
    je vais multiplier à loisir les services proposé par la classe que je suis en train de développer
    Je présume que l'on est d'accord jusque là, non

    Voyons la conséquence de cette décision : si tu multiplie à loisirs le nombre de services proposés par ta classe, l'interface de celle-ci devient d'office plus compliquée (ou "moins simple"), nous sommes toujours d'accord Admettons pour l'instant que l'on garde l'hypothèse comme "valide", mais réfléchissons un peu à ce que nous dit ISP :
    Citation Envoyé par ISP
    Clients should not be forced to depend upon interfaces that they do not use.

    (Les clients ne devraient pas êtres forcés de dépendre d'interfaces qu'ils n'utilisent pas (translation is mine)
    Cela signifie, en d'autres termes :
    Gardez vos interfaces aussi simples que possibles, de manière à ce que l'utilisateur n'ait pas accès à des services qu'il n'utilise pas
    On a donc le choix :
    • Soit on considère ton hypothèse de travail comme "correcte", mais on jette l'ISP aux orties, en entrainant avec lui l'OCP et le DIP,
    • soit on décide de respecter l'ISP, mais cela signifie que ton hypothèse de travail est mauvaise, et que tout ce que tu feras à partir de cette hypothèse tombe à l'eau.

    Dans ton article, tu as volontairement décidé de jeter l'ISP aux orties, puis tu viens nous dire (dans ta dernière intervention)
    oui, mais, regarde : dans cette situation l'ISP n'est pas respecté!
    Mais, à qui la faute

    C'est bien toi qui a décidé dés le départ de ne pas le respecter, non

    Tu essaye donc de justifier à posteriori une décision qui n'aurait jamais du être prise! Et, à partir de là, ton raisonnement s'effondre comme un château de cartes! :

    Si tu n'avais pas pris la décision d'exposer au niveau de la classe utilisatrice tous les services proposés par les données qu'elle utilise,
    1. tu aurais gardé une interface simple, en respectant d'avantage l'ISP et en te donnant au passage l'occasion de respecter l'OCP et le DIP;
    2. tu n'aurais pas jugé plus opportun d'appeler getComportement() pour que gereObstacles() (respectivement getSavoir() et afficheConnaissances()) puisse ne connaitre qu'un minimum de choses;
    3. la loi de Déméter aurait été respectée;
    4. et tout le monde aurait été content!

    Je t'ai peut être inutilement agressé en parlant d'ineptie, ce qui a sans doute eu pour effet de t'inciter à t'accrocher à la défense d'une position indéfendable.

    Mais, si tu prenais la peine de respirer un bon coup et de réfléchir calmement, logiquement, "mathématiquement" à ce que je viens de te dire (en gros, de la manière dont devrait réfléchir tout développeur aux problèmes auxquels il est confronté), n'arriverais tu pas effectivement à la conclusion que ta position est indéfendable car complètement erronée
    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

  5. #125
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 11
    Points : 0
    Points
    0
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Dans ton article, tu n'es pas occupé à émettre un postulat, tu émets une hypothèse de travail.

    La première chose à faire face à ce genre d'hypothèse est donc d'en prouver le bien-fondé au travers d'une démonstration (quitte à ne pas le faire dans ton article, soit).

    Le fait est que ton hypothèse de travail est fausse, autrement cela aurait été une thèse.

    A l'extrême limite, si tu avais dit que la classe utilisatrice expose un nombre de services correspondant à l'ensemble de toutes les combinaisons possibles que l'on peut obtenir en utilisant un ou plusieurs comportements des classes utilisées, j'aurais encore pu accepter, car c'est -- à peu près -- ce qu'il se passe effectivement. A ceci près :
    1. que certaines combinaisons sont redondantes ;
    2. que certaines combinaisons sont purement incohérentes par rapport au domaine traité (ex : si tu as un oeuf et un fouet électrique, tu les seules combinaisons possibles passent par le fait... de casser l'œuf en tout premier lieu )
    3. que KISS et YAGNI t'inciteront de toutes façons à ne fournir que les services dont tu as effectivement besoin à un instant T

    Le (1) et le (2) limite de facto le nombre de services "exposables"; le 3 fait que si multiplication des services il y a, elle sera suffisamment étalée dans le temps pour que, en tant que développeur de la classe, tu n'aies pas à t'inquiéter de leur nombre.

    D'accord, ce n'est pas hypothèse que je voulais dire. J'ignorais même qu'hypothèse de travail était une expression...
    Mais je penses que tu cherches trop la petite bête, hein ! Cela te fais perdre le sens général de la discussion malheureusement. Parce que quand j'utilise des mots dont je ne suis pas sûr, j'ai tendance à m'attarder pour préciser ma pensée, et si tu lis les 3 phrases que j'écris ensuite :

    - C'est mon exemple, donc j'en fixe les données, c'est normal.
    - Si tu refuses l'hypothèse de travail, tu passes à autre chose.
    - Mais si tu veux argumenter sur l'exemple principal de mon article, il faut en accepter les hypothèses.

    Chacune montre clairement que je pense à un postulat, donc pas de démonstration.
    Et soit dit en passant, ce postulat est que les types utilisés comme composantes internes sont également utilisés par le client par ailleurs.

    Ensuite tu compliques vraiment les choses : le raisonnement derrière le nombre de services à répliquer est très simple :
    Je compare formellement 2 conceptions : l'une qui permet de respecter Déméter, l'autre non. Evidemment, pour que la comparaison de leurs propriétés respectives ait un sens, le nombre de services doit être le même.
    Si c'est ce que tu veux dire, je ne considère pas le cas où Comportement, par exemple, aurait 5 méthodes publiques utiles à l'implémentation de Agent mais non nécessaires à l'utilisateur de Agent. Dans un tel cas, la version avec Déméter ne répliquerait naturellement pas ces 5 services, mais la version sans Déméter pourrait alors tout aussi bien ne pas exposer un Comportement entier mais une interface où ces 5 services sont absents !

    Citation Envoyé par koala01 Voir le message
    Mais c'est tout comme, à partir du moment où tu tiens à exposer tous les services proposés par les données utilisées.

    Il n'y a aucune différence entre se dire et se dire car, au final, ce à quoi l'utilisateur de ta classe va utiliser c'est... les données internes.

    Mais bon, continuons...
    Mais, le non respect de l'ISP, il vient de où à ton avis

    Cela va peut-être te surprendre, mais il ne vient que de ta décision aberrante, de ton ineptie (et je pèse mes mots) de vouloir exposer... tous les services proposés par les structures internes au niveau de ta classe utilisateur!

    En plus, a vouloir exposer les services proposés par tes structures internes, tu as raté une fantastique occasion d'appliquer le DIP et l'OCP en même temps.

    Et donc, forcément : à agir de la sorte, tu viens de jeter au moins trois principes essentiels de la programmation OO aux orties. Puis tu t'étonnes d'en arriver à la conclusion que Déméter ne sert à rien

    Allez, encore un petit effort, tu devrais pouvoir en profiter pour jeter également LSP et SRP aux orties, comme cela, le tableau sera complet


    Ne crois tu pas qu'il serait beaucoup plus sensé de revoir ton hypothèse de travail, d'appliquer SOLID (sans t'inquiéter de Déméter dans un premier temps) de manière scrupuleuse et voire, ensuite ce que cela donne au niveau de Déméter

    Je peux t'assurer que, en travaillant de la sorte, tu te rendra compte que Déméter est déjà respecté ... ou peu s'en faut!
    Il sera peut-être utile de créer des interfaces séparées, en effet... Il serait beaucoup plus utile de revoir ton hypothèse de travail
    Parce que tu as décidé -- en dépit de tout bon sens -- de le faire comme cela!!!

    Tu fais fausse route. Dans cet exemple, j'inverse la démonstration. Complètement.
    Je pars donc d'une classe Agent pour laquelle j'ai défini 7 services qui m'intéressent dans un premier temps. Et pour implémenter ces services, j'en suis venu à définir 2 classes internes. Comme ces classes internes se sont révélées bien correspondre à des concepts du domaine métier, j'ai décidé de soigner leur interface et d'en faire des composants réutilisables ailleurs que dans Agent. Et me voilà avec deux composantes de Agent : Comportement et Savoir.
    Tu vois qu'ici, on n'est pas du tout dans l'optique de répliquer les services des Composantes dans Agent. C'est plutôt l'inverse : chaque nouveau service de Agent est implémenté d'une manière ou d'une autre, parfois dans Agent seule, parfois dans une Composante seule, et parfois dans tout (affiche).
    Tes conclusions sont donc hors de propos.
    Citation Envoyé par koala01 Voir le message
    Admets que cette idée de vouloir exposer tous les services proposés par les données utilisée est une connerie monumentale, fais marche arrière à ce niveau là, et tu verras que toutes tes objections tomberont les unes après les autres!

    A la limite, ton article suit un raisonnement par l'absurde pour justement démontrer ce qu'il ne faut pas faire
    Je te lis depuis qq jours, koala01, et tu ne cesses de tenir des propos déplacés, de sortir de grands mots, comme si tu avais un cours à donner. Et d'un autre côté, je constate que tu es à côté de la plaque presque tout le temps. C'est bizarre, non ?

  6. #126
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 11
    Points : 0
    Points
    0
    Par défaut
    Citation Envoyé par leternel Voir le message
    Par contre, tu perds la possibilité d'avoir un agent qui choisit son comportement parmi plusieurs, en fonction de ce qu'il estime être le besoin.
    Tu perds aussi la possibilité d'avoir un Agent qui implémente son propre comportement.
    Non, non, c'est un exemple bien sur. Si tu veux avoir ça tu fais du dynamique. Par exemple unique_ptr<Comportement> m_pComportement;
    C'est vraiment un détail. J'écris les choses les plus simples pour les besoins de la démonstration.

  7. #127
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 11
    Points : 0
    Points
    0
    Par défaut
    Citation Envoyé par mintho carmo Voir le message
    Le problème est peut être que tu n'as pas lu ton propre article ?



    Je te cite :



    Tu es passé d'une affirmation dans ton article à une possibilité dans ton dernier message. C'est pas exactement la même chose...
    L'affirmation dans mon article est que Déméter est une tromperie.

    La possibilité que j'évoque et que tu cites :
    >Le propos de mon article est de montrer que de tels chaînages invalides peuvent être légitimes
    >(en dehors des cas >d'exceptions établis), en cas d'architecture ouverte (Cf mon post précédent).
    est l'existence de contre-exemples à Déméter qui ne fasse pas partie des cas d'exception connus.
    Autrement-dit, si tu te trouves dans de tels cas et que tu appliques Déméter (logique car pas un cas d'exception), tu risques de déteriorer le design.

    Cela correspond bien à l'affirmation, non ?

    Le jour où cette loi incluera dans ces exceptions les cas que je mets en avant, elle cessera de tromper.

    En fait, je dis également qu'elle est inutile dans les cas où elle fonctionne bien car des bonnes pratiques plus simples, plus fondamentales, et qui font concensus, suffisent à ne pas générer les chaînages interdits.



    Citation Envoyé par mintho carmo Voir le message
    Si tu avais étudié les cas limites de la loi de Déméter dans ton article, en montrant que cette loi admet des exceptions, cela ne poserait pas de problème. Et personne ne t'aurait contredit.
    Pour ce qui est des exceptions connues, si c'est ce que tu veux dire, je ne les dénonce pas, et à juste titre : ce serait enfoncer une porte ouverte !
    Pour le reste, comme je l'ai dit juste avant, c'est le propos de mon article que de mettre en avant une classe de cas importants qui "posent problème" à cette loi selon moi.
    En dehors de ces cas, la loi est parfaitement valide et je le dis. J'ajoute simplement qu'elle est inutile car... cf plus haut.

    Citation Envoyé par mintho carmo Voir le message
    ...

  8. #128
    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 igor_ Voir le message
    - C'est mon exemple, donc j'en fixe les données, c'est normal.
    Oui, et les données que tu fixes à ce sujet sont -- en gros -- "Rien à foutre de l'ISP"...
    - Si tu refuses l'hypothèse de travail, tu passes à autre chose.
    Oui, parce que, à partir du moment où tu décide expressément de ne pas respecter les fondamentaux de la conception, au mieux, tu fonces dans un mur, au pire, ton travail perd toutte crédibilité!
    - Mais si tu veux argumenter sur l'exemple principal de mon article, il faut en accepter les hypothèses.
    C'est ce que j'ai fait dans ma dernière intervention... Du moins, aussi longtemps que possible. Car, une fois qu'il est démontré que l'hypothèse est fausse, tout le raisonnement tombe à l'eau

    Chacune montre clairement que je pense à un postulat, donc pas de démonstration.
    Oui, mais un postulat n'a besoin d'aucune preuve : on croit en Dieu, quel que soit le nom qu'on lui donne, ou non... Personne ne sera capable d'affirmer ou d'infirmer ce postulat.

    Le développement informatique ne peut pas se contenter de postulat, car il ne connait que "vrai" et "faux", sans aucune place pour le "peut-être". Si bien que toute hypothèse formulée à ce sujet doit pouvoir être démontrée logiquement, "mathématiquement" dirais-je
    Et soit dit en passant, ce postulat est que les types utilisés comme composantes internes sont également utilisés par le client par ailleurs.
    Ca, c'est peut être la seule hypothèse démontrable de ton raisonnement. Car, effectivement, les types utilisés comme composantes internes sont régulièrement utilisées seule "par ailleurs"...
    Ensuite tu compliques vraiment les choses : le raisonnement derrière le nombre de services à répliquer est très simple :
    Ben, tu pars dans une démonstration par l'absurde, en refusant une évidence : ton hypothèse est caduque. Je ne fais que pousser le raisonnement à l'extrême
    Je compare formellement 2 conceptions : l'une qui permet de respecter Déméter, l'autre non. Evidemment, pour que la comparaison de leurs propriétés respectives ait un sens, le nombre de services doit être le même.
    Pourquoi une classe ne doit exposer que les services strictement nécessaires à son utilisation, et cela te permettra de respecter Déméter.

    Tu peux très bien avoir une classe avec trois accesseurs (sur des données internes) qui ne respecte absolument pas Déméter et la même classe, exposant cinq services que l'on est effectivement en droit d'attendre de la part de la classe qui respectera scrupuleusement Déméter, simplement parce que toute notion de donnée interne sont absentes de son interface
    Si c'est ce que tu veux dire, je ne considère pas le cas où Comportement, par exemple, aurait 5 méthodes publiques utiles à l'implémentation de Agent mais non nécessaires à l'utilisateur de Agent.
    Et pourtant, c'est pour ainsi dire le seul cas qui mérite d'être considéré!!!

    Car il faut bien comprendre que si tu as décidé d'utiliser une donnée de type Comportement dans ta classe Agent, c'est quand même pour une bonne raison : ta classe Comportement est capable de fournir des services qui aideront ta classe Agent dans sa tâche. Si elle n'avait pas eu cet intérêt majeur, tu aurais tout aussi bien pu "dupliquer" toutes les données privées de Comportement dans ta classe Agent et les manipuler "tout simplement" (en dupliquant sans doute au passage toute la logique mise en place par les différents services offerts par Comportement)
    Dans un tel cas, la version avec Déméter ne répliquerait naturellement pas ces 5 services, mais la version sans Déméter pourrait alors tout aussi bien ne pas exposer un Comportement entier mais une interface où ces 5 services sont absents !
    Ben oui, bien sur!!! Et en échange, elle peut exposer deux, trois, cinq ... quinze (meme, si tu veux) services qui utilisent comportements mais pour lesquels l'utilisateur de ta classe Agent n'a absolument aucun besoin de savoir qu'il manipule une donnée de type Comportement "en arrière plan".
    Tu fais fausse route. Dans cet exemple, j'inverse la démonstration. Complètement.
    Je pars donc d'une classe Agent pour laquelle j'ai défini 7 services qui m'intéressent dans un premier temps. Et pour implémenter ces services, j'en suis venu à définir 2 classes internes. Comme ces classes internes se sont révélées bien correspondre à des concepts du domaine métier, j'ai décidé de soigner leur interface et d'en faire des composants réutilisables ailleurs que dans Agent.
    Et me voilà avec deux composantes de Agent : Comportement et Savoir.
    Et tu as raison d'agir de la sorte...

    Jusqu'au moment où tu décides de te mettre dans une situation dans laquelle tu dois connaitre Comportement et Savoir pour pouvoir utiliser ta classe Agent... Ca brise l'encapsulation, ca birse l'ISP, et ca brise Déméter (et ca la fout mal pour l'OCP, entre autres-
    Je te lis depuis qq jours, koala01, et tu ne cesses de tenir des propos déplacés, de sortir de grands mots, comme si tu avais un cours à donner. Et d'un autre côté, je constate que tu es à côté de la plaque presque tout le temps. C'est bizarre, non ?
    Tu m'accorde à vrai dire la crédibilité que tu veux, bien sur... Tu as l'impression que je "pête plus haut que mon cul" et que "je ne sais absolument pas de quoi je parle" libre à toi de le croire

    Mais observe un tout petit peu mes statistiques sur le forum et penses quand même au fait que, pour avoir à peu près le double de points que d'interventions, j'ai quand même du avoir un sacré nombre de votes positifs, et que je ne les ai pas obtenus en n'intervenant que sur des questions à débat, très loin de là

    Penses aussi que je suis (eh oui, j'en suis particulièrement fier )l'auteur d'un livre dont l'appréciation sur les différents forums est excellente et qui est référencé au CNES dans la bibliographie pour les prochaines règles qualité en C, C++ et embarqué.

    Peut-être serait il donc temps de faire une légère introspection personnelle (promis, si tu fais la tienne, je fais la mienne) et de se demander "qui est à coté de la plaque"... Qu'en penses tu

    EDIT : d'ailleurs, au passage!!! Sachant qu'il est impossible de voter pour ou contre ses propres interventions (et que je n'ai donc pas "truqué" les votes), tu pourras te faire une idée de qui est le plus crédible en comparant le nombre de votes positifs que j'ai recu depuis que tu as déterré le sujet avec le nombre de vote négatifs que tu as obtenu dans le même laps de temps... Cela ne te donne vraiment pas envie de reconsidérer ton approche
    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

  9. #129
    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 igor_ Voir le message
    >Le propos de mon article est de montrer que de tels chaînages invalides peuvent être légitimes
    >(en dehors des cas >d'exceptions établis), en cas d'architecture ouverte (Cf mon post précédent).
    est l'existence de contre-exemples à Déméter qui ne fasse pas partie des cas d'exception connus.
    Autrement-dit, si tu te trouves dans de tels cas et que tu appliques Déméter (logique car pas un cas d'exception), tu risques de déteriorer le design.

    Cela correspond bien à l'affirmation, non ?
    A vrai dire (mais bon, je suis peut être un tout petit peu extrémiste sur le sujet, je te l'accorde), il n'y a pas d'exception qui tienne réellement la route que ce soit pour Déméter ou pour SOLID.

    Je penses en effet de plus en plus que, lorsque l'on se trouve dans une situation dans laquelle il faut "sortir l'exception" relative à l'un de ces principes (ou à cette loi), c'est qu'il y a un problème de conception qui nous a déjà placé dans cette situation, et que l'exception que l'on décidera d'accepter n'aura pour seul but que de contourner les conséquence du problème de conception précédant et pour seule conséquence... que de nous obliger à accepter d'autres exceptions par la suite.

    En un mot comme en cent : quand tu commence à avoir besoin de faire appel à une exception pour Déméter ou pour SOLID, tu commences à construire un mur dans lequel tu finiras tôt ou tard par t'emplafonner brutalement

    Mais bon, je le redis et je l'avoue sans honte j'ai tendance à être extrémiste sur le sujet
    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

  10. #130
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    La loi de Déméter est un principe fondamental. Alors certes ça peut être contraignant au début, on peut ne pas vraiment comprendre pourquoi "faire du code" supplémentaire alors que ça peut très bien "marcher" sans.. mais quid en terme de qualité, de cohésion et de fonctionnel à moyen et long termes ?

    Dans l'article il est écrit "Prenons l’exemple plus neutre de la prise de rendez-vous avec un médecin". Voilà le style de raccourcit qu'interdit la loi de Déméter, personne ne prend rendez-vous avec un médecin, mais avec un cabinet dont le fait qu'il y soit (encore) médecin n'est qu'une supposition quant à la composante de son implémentation, de son organisation de la structure avec laquelle on souhaite prendre rendez-vous.

    Et si c'est le médecin directement, ça passera toujours par une structure, certes unipersonnelle mais structure quand même. Et si ça le fait chier de recevoir les appels alors qu'il a une secrétaire pour ça, alors pourquoi ce con a-t-il redirigé le numéro de la structure vers son portable ? Ou pourquoi c'est le téléphone dans son local qui sonne et non pas celui de la secrétaire ? En tout cas ça veut dire que son organisation, son implémentation n'est pas correcte, pas évolutive et il y a carrément un problème de conception qui n'a rien à voir avec celui qui prend rendez-vous (l'utilisateur du service supposé).

    Demain c'est mon tour d'amener les petits pains, j'ai pris commande non pas avec le boulanger, mais avec la boulangerie..

    Pour l'exemple de chien.getPattes().cours(), ça peut "marcher", ou plutôt "courir" (ha ha ha que je suis drôle, pardonnez moi je suis fatigué) mais si demain ça demande à ce qu'en prérequis le cerveau doive sortir de son sommeil, localiser le bâton après quoi courir, la mâchoire pour l'attraper, le cerveau à nouveau pour localiser son maître afin de le rapporter, le manière la plus pragmatique est de coupler les pattes avec le cerveau et la mâchoire en passant par le chien, bref, tout est couplé et on ne peut plus réutiliser l'ingénierie des pattes sur un chat ou un lapin.

    Et c'est là où commence l'effet "plat de spaghetti", une des pires erreurs bien que facile à faire et pourtant tellement simple à éviter lorsque l'on fait jouer la cohérence..

    "Low coupling, high cohesion"

    Après peut-être que dans les langages interprétés ça peut faire un gain de performances exécutives, ça je ne sais pas, mais ça ne change rien à ce niveau là pour les langages compilés
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  11. #131
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 11
    Points : 0
    Points
    0
    Par défaut
    Citation Envoyé par mister3957 Voir le message
    La loi de Déméter est un principe fondamental. Alors certes ça peut être contraignant au début, on peut ne pas vraiment comprendre pourquoi "faire du code" supplémentaire alors que ça peut très bien "marcher" sans.. mais quid en terme de qualité, de cohésion et de fonctionnel à moyen et long termes ?

    Dans l'article il est écrit "Prenons l’exemple plus neutre de la prise de rendez-vous avec un médecin". Voilà le style de raccourcit qu'interdit la loi de Déméter, personne ne prend rendez-vous avec un médecin, mais avec un cabinet dont le fait qu'il y soit (encore) médecin n'est qu'une supposition quant à la composante de son implémentation, de son organisation de la structure avec laquelle on souhaite prendre rendez-vous.

    Et si c'est le médecin directement, ça passera toujours par une structure, certes unipersonnelle mais structure quand même. Et si ça le fait chier de recevoir les appels alors qu'il a une secrétaire pour ça, alors pourquoi ce con a-t-il redirigé le numéro de la structure vers son portable ? Ou pourquoi c'est le téléphone dans son local qui sonne et non pas celui de la secrétaire ? En tout cas ça veut dire que son organisation, son implémentation n'est pas correcte, pas évolutive et il y a carrément un problème de conception qui n'a rien à voir avec celui qui prend rendez-vous (l'utilisateur du service supposé).

    Demain c'est mon tour d'amener les petits pains, j'ai pris commande non pas avec le boulanger, mais avec la boulangerie..

    Pour l'exemple de chien.getPattes().cours(), ça peut "marcher", ou plutôt "courir" (ha ha ha que je suis drôle, pardonnez moi je suis fatigué) mais si demain ça demande à ce qu'en prérequis le cerveau doive sortir de son sommeil, localiser le bâton après quoi courir, la mâchoire pour l'attraper, le cerveau à nouveau pour localiser son maître afin de le rapporter, le manière la plus pragmatique est de coupler les pattes avec le cerveau et la mâchoire en passant par le chien, bref, tout est couplé et on ne peut plus réutiliser l'ingénierie des pattes sur un chat ou un lapin.

    Et c'est là où commence l'effet "plat de spaghetti", une des pires erreurs bien que facile à faire et pourtant tellement simple à éviter lorsque l'on fait jouer la cohérence..

    "Low coupling, high cohesion"

    Après peut-être que dans les langages interprétés ça peut faire un gain de performances exécutives, ça je ne sais pas, mais ça ne change rien à ce niveau là pour les langages compilés

    Si un médecin libéral travaillant avec une secrétaire vous fait la commande d'un logiciel permettant de modéliser et tracer les interactions entre lui, sa secrétaire et le patient lors de la prise de RV, on peut imaginer 2 cas de figure :
    - vous faites ce qu'il vous a demandé et vous serez payé.
    - vous estimez que, dans le besoin exprimé, seul compte vraiment le point de vue du patient et qu'il faut abstraire le reste. Vous créer donc une interface abstraite offrant au patient tous les services nécessaires à sa prise de rendez-vous, et vous implémentez ces services de manière interne. Vous êtes plutôt fier de votre conception, car vous avez su aller au-delà du besoin exprimé. Lorsque vous montrez votre prototype au médecin, vous commencez par lui vanter les capacités d'adaptation de votre architecture : le patient ne dialoguant qu'avec une interface abstraite (un "cabinet médical"), le logiciel pourra fonctionner avec un ou plusieurs médecins, zéro ou un ou plusieurs secrétaires, et même en l'absence de tout personnel, en prévoyant des comportement par défaut. Tout ce qu'il y aura à faire, c'est d'implémenter de nouveaux comportements. l'interface principale, elle, restera inchangée. Alors le médecin vous répond : "Mais je vous avais pourtant bien dit que ce que nous avions besoin, c'était de modéliser les interactions directes entre moi, ma secrétaire, et le patient. C'est tout-à-fait impossible avec votre application. Vous avez créé un mur qui empêche cela.

    mister3957, comme beaucoup d'intervenants, vous vous précipitez pour imaginer des besoins. Et si et si et si. Je ne dis pas que vos généralisations et vos abstractions ne sont pas bonnes. Elles sont excellentes et plutôt naturelles. Mais, simplement, elles sont hors sujet ici. Dans mon article, l'exemple du médecin explicite des entités claires, et il exprime clairement la problématique de la prise de RV en termes d'interactions entre ces entités. Vous pouvez proposer toute autre modélisation, abstraite à souhait, aucun souci. Mais c'est alors un autre cas d'étude. Vous pouvez dire que ma modélisation ne peut correspond à aucun problème en pratique et qu'elle ne sert donc à rien, mais c'est une position difficile à tenir : il est plus facile d'affirmer qu'une modélisation peut correspondre à des cas réels que l'inverse. J'ai tenté de précisé un cas réel plus haut.

    Enfin, cet exemple du médecin et avant tout une image. Dans mon article, je ne le détaille pas plus que l'exemple du chien qui est une image également. On ne donne pas le contre-pied d'une image par une modélisation complexe, mais par une autre image. C'est donc normal que l'exemple du médecin paraisse si simple. Mais il serait hors-sujet de dire qu'elle est simpliste, comme ont pu le dire des intervenants. On ne dit pas d'une image qu'elle est simpliste car c'est le but d'une image que de saisir l'essence d'un concept ou d'une problématique. Je n'ai pas dit de l'image du chien qu'elle était simpliste, et je trouve qu'elle illustre bien le cas général (le plus fréquent à mon avis) où Déméter convient. Et je n'ai donc pas tenté d'élaborer ma propre modélisation du chien, plus complexe, pour aller dans mon sens : cela aurait été hors-sujet.
    Vous trouverez facilement sur stack-overflow des contre-images visant à montrer intuitivement qu'on peut trouver de nombreux exemples où Déméter est contre-productif.

    Encore une fois, mon article repose sur l'existence de tels cas. C'est une position facile à tenir à mon humble avis. Quant aux cas où Déméter fonctionne bien, je les traite explicitement dans la dernière section "Déméter et encapsulation". Les nombreux intervenants qui ont tenté d'invalider mon article illustrant leurs propos par des cas où on expose des types internes, qui n'ont vocation qu'à être utilisés par l'implémentation, n'ont soit pas compris le point, soit pas lu mon article jusqu'au bout.

    -------------

    Je trouve dommage que, sur un forum de programmation qui se veut professionnel, lorsqu'un nouveau point de vue est apporté sur un sujet où l'essentiel des publications se contente de vulgariser ce que le lecteur peut lui-même trouver facilement sur le net, on puisse assister à un tel tir de barrage. Avec autant de défauts de lecture évidents, de propos hors-sujet ou déplacés, de jugements sur la personne plutôt que sur les idées pour certains je pense en réalité qu'il s'agit plus d'un effet d'extrémisme idéologique : certains semblent vouer une passion pour certains principes de conception, et il est facile d'être piqué quand on est passionné. Mais la passion est rarement une bonne chose en matière de programmation comme ailleurs. Ne soyez pas esclaves de vos principes. Chaque situation a ses caractéristiques propres, et beaucoup ne peuvent satisfaire simultanément tous ces principes. Connaître et apprendre ce principes est très bien, mais les appliquer a priori, automatiquement, sans réfléchir en premier lieu aux caractéristiques concrètes de chaque situation risque de conduire à des conceptions inadaptées, et souvent excessivement abstraites.

    Je clos ici ma participation à cette discussion, et laisse place au ballet fascinant des +1 -1.

  12. #132
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Le problème, c'est que tu ne sembles pas avoir saisi le sens de la Loi de demeter.

    Elle dit de ne pas exposer la structure de la classe, pas d'interdire l'accès au contenu sémantique.

    D'un autre côté, si ta fonction n'agit que sur un comportement, pourquoi prend-elle en argument un Agent, et pas seulement le comportement?

    S'il s'agit comme tu le dis de modéliser les interactions, alors c'est une modélisation, qui n'expose pas le fonctionnement interne du moteur de modélisation.
    Par contre, il doit fournir un ensemble de propriété observable (une map d'identifiant vers des valeurs?), et d'unités de prise de décision (des foncteurs?).

    Ces agents d'une modélisation n'ont pas à être conçus (de prime abord) comme des médecins, des patients ou des secrétaires.

    Je t'invite d'ailleurs à regarder ce qu'est un ECS (entity component system).
    On a eu pas mal de discussions à ce sujet, l'an dernier; celle-ci, par exemple.


    Quant à l'avis sur nos lectures de ton article, si tu trouves qu'autant de gens n'ont pas compris ton propos, c'est probablement parce qu'il est mal exprimé.
    J'ai personnellement trouvé ton article sensationnaliste, c'est à dire affirmatif, avec en guise de preuve des exemples (forcément arbitraires et partiels)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  13. #133
    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 igor_ Voir le message
    Si un médecin libéral travaillant avec une secrétaire vous fait la commande d'un logiciel permettant de modéliser et tracer les interactions entre lui, sa secrétaire et le patient lors de la prise de RV, on peut imaginer 2 cas de figure :
    - vous faites ce qu'il vous a demandé et vous serez payé.
    - vous estimez que, dans le besoin exprimé, seul compte vraiment le point de vue du patient et qu'il faut abstraire le reste. Vous créer donc une interface abstraite offrant au patient tous les services nécessaires à sa prise de rendez-vous, et vous implémentez ces services de manière interne. Vous êtes plutôt fier de votre conception, car vous avez su aller au-delà du besoin exprimé. Lorsque vous montrez votre prototype au médecin, vous commencez par lui vanter les capacités d'adaptation de votre architecture : le patient ne dialoguant qu'avec une interface abstraite (un "cabinet médical"), le logiciel pourra fonctionner avec un ou plusieurs médecins, zéro ou un ou plusieurs secrétaires, et même en l'absence de tout personnel, en prévoyant des comportement par défaut. Tout ce qu'il y aura à faire, c'est d'implémenter de nouveaux comportements. l'interface principale, elle, restera inchangée. Alors le médecin vous répond : "Mais je vous avais pourtant bien dit que ce que nous avions besoin, c'était de modéliser les interactions directes entre moi, ma secrétaire, et le patient. C'est tout-à-fait impossible avec votre application. Vous avez créé un mur qui empêche cela.
    Ou la! tu mélange tout là...

    Ce n'est pas parce que l'on dit "il ne faut pas que la prise de rendez vous (l'interaction client <-->cabinet) ne passe par la secrétaire, que l'on n'est pas sur d'avoir" que cela ne veut pas dire que le cabinet n'a effectivement pas de secrétaire ni qu'il est impossible de tracer les interaction entre trois acteurs principaux que sont le(s) toubib(s), la (les) secrétaire(s) et le(s) patient(s).

    On dit juste que cela doit être transparent au niveau de la prise de rendez-vous (le patient se fout pas mal de savoir s'il parle à la secrétaire, au docteur ou à un robot lorsqu'il prend rendez-vous : ce qu'il veut c'est une date, une heure et... un peu de temps pour s'organiser afin de pouvoir y être) que, s'il y a "autre chose" à faire entre les différentes interaction -- noter l'heure des appels, leur origine, leur destinataires, leur motifs, par exemple -- cela doit se faire de manière automatique (sans que les intervenant n'en aient forcément conscience) et que, si on veut accéder à ces données par la suite, ca doit se faire "par un autre chemin que celui de la prise de rendez-vous"

    Ton approche semble partir du principe que l'on va essayer d'accéder à ces données exactement de la même manière que celle utilisée... pour créer ces données. Or, le principe de base est de créer les données d'un coté pour pouvoir les utiliser de l'autre. Même dans un atelier d'ébénisterie, les machines qui permettent de débiter et de préparer les planches sont "physiquement" séparées des établis sur lesquels on les peaufine, on les adapte et on les assemble!

    Je trouve dommage que, sur un forum de programmation qui se veut professionnel, lorsqu'un nouveau point de vue est apporté sur un sujet où l'essentiel des publications se contente de vulgariser ce que le lecteur peut lui-même trouver facilement sur le net, on puisse assister à un tel tir de barrage.
    Généralement, tu peux te dire que les tirs de barrage, lorsqu'ils viennent de certaines personnes, sont pour le moins justifié
    Avec autant de défauts de lecture évidents, de propos hors-sujet ou déplacés, de jugements sur la personne plutôt que sur les idées pour certains je pense en réalité qu'il s'agit plus d'un effet d'extrémisme idéologique : certains semblent vouer une passion pour certains principes de conception, et il est facile d'être piqué quand on est passionné.
    Oui, je suis passionné par le sujet et par le développement en C++ dans son ensemble, mais non, je ne suis pas piqué quand je croise quelqu'un qui n'est pas de mon avis : j'essaye de lui expliquer les défauts que je croise dans son cheminement intellectuel.
    Mais la passion est rarement une bonne chose en matière de programmation comme ailleurs. Ne soyez pas esclaves de vos principes. Chaque situation a ses caractéristiques propres, et beaucoup ne peuvent satisfaire simultanément tous ces principes. Connaître et apprendre ce principes est très bien, mais les appliquer a priori, automatiquement, sans réfléchir en premier lieu aux caractéristiques concrètes de chaque situation risque de conduire à des conceptions inadaptées, et souvent excessivement abstraites.
    Même si je reconnais volontiers que je suis de plus en plus extrémiste au sujet des principes fondamentaux, il ne faut pas croire que je sois l'esclave de mes principes.

    J'ai essayé de t'expliquer le fait que tu pars d'une hypothèse dans laquelle tu décide volontairement de ne pas respecter l'ISP, que c'est une très mauvaise idée en soi, mais bon après tout, pourquoi pas

    Le problème, c'est que, par la suite, tu nous dis "oui, mais l'ISP n'est pas respecté, et du coup, Déméter ne sert à rien, que ce n'est qu'un leurre" (je reprend tes propres termes)

    C'est un peu comme si je disais " je me fous royalement de l'étude de sol, que ma maison sera construite sur du sable, je fais ma maison comme bon me semble, sans creuser de fondations et sans mettre une dalle de béton en dessous" puis que ... j'allais gueuler chez celui qui a dressé le plan parce que ma maison penche comme la tour de Pise. N'aurais tu pas tendance à me dire que "je l'ai bien cherché" j'ai volontairement fait une connerie dans la conception de ma maison, j'en paye forcément le prix à un moment ou à un autre.

    Eh bien là, c'est pareil : tu fais volontairement une connerie au début de ton raisonnement, puis tu t'étonne que l'on te dise que ton raisonnement est faux parce que basé sur une hypothèse dénuée de bon sens

    Maintenant, je suis peut être moi même victime d'une erreur dans mon propre raisonnement. Peut être que je vais trop loin en disant que tu pars d'une hypothèse dans laquelle tu n'as rien à foutre de l'ISP; Peut être la multiplication des services à laquelle on assiste dans ton raisonnement n'a rien à voir avec le respect de l'ISP D'accord... Prouve moi que je fais erreur!

    Prouve moi que l'on ne respecte pas moins bien l'ISP quand on expose 5 fonctions que quand on en expose 3, surtout si les deux fonctions supplémentaire on trait à des données internes différentes.

    Démontre moi que le fait d'exposer -- sous une forme ou sous une autre -- tous les services proposés par une donnée interne ne revient pas à bêtement fournir un accesseur dessus.

    Après tout, voilà en gros les deux bases du raisonnement que j'ai suivi pour démontrer que ton raisonnement était faux. Invalide ces deux hypothèses (ou ne serait-ce que l'une d'entre-elles), et tu invalidera mon raisonnement. Et si tu y arrives, j'accepterai ton raisonnement ou, du moins, j'arrêterai de le démolir en publique, en plus de te faire mes plus plates excuses
    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

  14. #134
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par igor_ Voir le message
    je pense en réalité qu'il s'agit plus d'un effet d'extrémisme idéologique : certains semblent vouer une passion pour certains principes de conception, et il est facile d'être piqué quand on est passionné.
    Et toi, sais tu te remettre en question ? N'es tu pas "passionné" par ton "extrémisme idéologique", au point d'avoir du mal à accepter que tu puisses te tromper, que tu as peut être mal compris la loi de Déméter, que tes exemples ne sont pas pertinents ? Et peut être aussi un peu "piqué" que ton article n'a pas eu les retours que tu aurais voulu...

  15. #135
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Citation Envoyé par igor_ Voir le message
    Si un médecin libéral travaillant avec une secrétaire vous fait la commande d'un logiciel permettant de modéliser et tracer les interactions entre lui, sa secrétaire et le patient lors de la prise de RV, on peut imaginer 2 cas de figure :
    - vous faites ce qu'il vous a demandé et vous serez payé.
    - vous estimez que, dans le besoin exprimé, seul compte vraiment le point de vue du patient et qu'il faut abstraire le reste. Vous créer donc une interface abstraite offrant au patient tous les services nécessaires à sa prise de rendez-vous, et vous implémentez ces services de manière interne. Vous êtes plutôt fier de votre conception, car vous avez su aller au-delà du besoin exprimé. Lorsque vous montrez votre prototype au médecin, vous commencez par lui vanter les capacités d'adaptation de votre architecture : le patient ne dialoguant qu'avec une interface abstraite (un "cabinet médical"), le logiciel pourra fonctionner avec un ou plusieurs médecins, zéro ou un ou plusieurs secrétaires, et même en l'absence de tout personnel, en prévoyant des comportement par défaut. Tout ce qu'il y aura à faire, c'est d'implémenter de nouveaux comportements. l'interface principale, elle, restera inchangée. Alors le médecin vous répond : "Mais je vous avais pourtant bien dit que ce que nous avions besoin, c'était de modéliser les interactions directes entre moi, ma secrétaire, et le patient. C'est tout-à-fait impossible avec votre application. Vous avez créé un mur qui empêche cela.

    mister3957, comme beaucoup d'intervenants, vous vous précipitez pour imaginer des besoins. Et si et si et si. Je ne dis pas que vos généralisations et vos abstractions ne sont pas bonnes. Elles sont excellentes et plutôt naturelles. Mais, simplement, elles sont hors sujet ici. Dans mon article, l'exemple du médecin explicite des entités claires, et il exprime clairement la problématique de la prise de RV en termes d'interactions entre ces entités. Vous pouvez proposer toute autre modélisation, abstraite à souhait, aucun souci. Mais c'est alors un autre cas d'étude. Vous pouvez dire que ma modélisation ne peut correspond à aucun problème en pratique et qu'elle ne sert donc à rien, mais c'est une position difficile à tenir : il est plus facile d'affirmer qu'une modélisation peut correspondre à des cas réels que l'inverse. J'ai tenté de précisé un cas réel plus haut.

    Enfin, cet exemple du médecin et avant tout une image. Dans mon article, je ne le détaille pas plus que l'exemple du chien qui est une image également. On ne donne pas le contre-pied d'une image par une modélisation complexe, mais par une autre image. C'est donc normal que l'exemple du médecin paraisse si simple. Mais il serait hors-sujet de dire qu'elle est simpliste, comme ont pu le dire des intervenants. On ne dit pas d'une image qu'elle est simpliste car c'est le but d'une image que de saisir l'essence d'un concept ou d'une problématique. Je n'ai pas dit de l'image du chien qu'elle était simpliste, et je trouve qu'elle illustre bien le cas général (le plus fréquent à mon avis) où Déméter convient. Et je n'ai donc pas tenté d'élaborer ma propre modélisation du chien, plus complexe, pour aller dans mon sens : cela aurait été hors-sujet.
    Vous trouverez facilement sur stack-overflow des contre-images visant à montrer intuitivement qu'on peut trouver de nombreux exemples où Déméter est contre-productif.

    Encore une fois, mon article repose sur l'existence de tels cas. C'est une position facile à tenir à mon humble avis. Quant aux cas où Déméter fonctionne bien, je les traite explicitement dans la dernière section "Déméter et encapsulation". Les nombreux intervenants qui ont tenté d'invalider mon article illustrant leurs propos par des cas où on expose des types internes, qui n'ont vocation qu'à être utilisés par l'implémentation, n'ont soit pas compris le point, soit pas lu mon article jusqu'au bout.

    -------------

    Je trouve dommage que, sur un forum de programmation qui se veut professionnel, lorsqu'un nouveau point de vue est apporté sur un sujet où l'essentiel des publications se contente de vulgariser ce que le lecteur peut lui-même trouver facilement sur le net, on puisse assister à un tel tir de barrage. Avec autant de défauts de lecture évidents, de propos hors-sujet ou déplacés, de jugements sur la personne plutôt que sur les idées pour certains je pense en réalité qu'il s'agit plus d'un effet d'extrémisme idéologique : certains semblent vouer une passion pour certains principes de conception, et il est facile d'être piqué quand on est passionné. Mais la passion est rarement une bonne chose en matière de programmation comme ailleurs. Ne soyez pas esclaves de vos principes. Chaque situation a ses caractéristiques propres, et beaucoup ne peuvent satisfaire simultanément tous ces principes. Connaître et apprendre ce principes est très bien, mais les appliquer a priori, automatiquement, sans réfléchir en premier lieu aux caractéristiques concrètes de chaque situation risque de conduire à des conceptions inadaptées, et souvent excessivement abstraites.

    Je clos ici ma participation à cette discussion, et laisse place au ballet fascinant des +1 -1.
    Je ne comprends pas ta réaction, pourquoi tu te sens offensé comme ça, il est où le problème ?

    Tu sous entends donc que l'on suive des principes fondamentaux juste comme ça pour se faire plaisir, qu'on travaille juste pour assouvir notre passion de manière égoïste sans penser aux besoins ? En somme que l'on a rien à voir avec des ingénieurs mais qu'on est juste des geeks qui veulent "jouer à l'ordinateur" en oubliant tout le reste à différents termes c'est bien ça ?

    Je te trouve très méprisant et carrément anti constructif dans la mesure où le sujet que tu poses et les questions qui vont avec sont excellentes et n'ont pas lieu à un débat mais à une recherche instructive et intellectuelle.

    Si tu n'es pas assez ouvert pour recevoir des réponses lorsqu'elles ne collent pas avec ce que tu attends, pourquoi tu t'exposes comme ça sur un forum ? Et bien sûr c'est la faute du forum et des guignoles qui le composent en cherchent des points, un score, une popularité etc.. J'en ai connu des gens qui se sentait au dessus des autres, mais un comportement comme le tiens ça vise le top du top du négatif !

    A un moment donné quand tu penses que tout le monde se trompe, il y a des questions à se poser, c'est peut-être pas l'écosystème qui a un problème, mais toi.

    Je pose ma question : d'où vient cette frustration ? T'as connu un sale truc récemment ou quelque chose comme ça ?

    Ce que tu racontes est tout sauf constructif, ça ne vaut rien à moyen et long termes. Ok on peut être contraint à user de pragmatisme mais pour se faire il faut absolument cette couche d'abstraction qui puisse faire en sorte que ça soit possible, rentable à termes et surtout qui ne soit pas gangreneux, et ça c'est pas la responsabilité du client, c'est la notre en adéquation avec le contexte.

    Il n'y a qu'un seul type de motivation qui agirait consciemment comme ça, c'est le genre de fournisseur qui vise la dépendance pour tenir son client par les couilles dans l'idée de le démonter à niveau maintenance. Permets moi d'avoir des doutes quand à ce type d'agissement, des gens qui l'alimentent ainsi que l'intérêt des clients à terme.
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  16. #136
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    J'ai survolé les derniers propos et j'ai beaucoup aimé l'exemple de Bousk.

    Il y a je pense moyen de mettre de converger -- pas forcément de beaucoup, mais un peu.
    Il y a des soucis de fuite d'abstraction quand on parle de médecin, de secrétaire, etc.

    Le cabinet va proposer plusieurs services/cas d'utilisation.
    - Obtenir/"éditer" un RDV
    - consulter
    et possiblement d'autres.

    On ne va pas contacter le médecin, mais le cabinet. Là, on va être redirigés vers l'interface de prise de RDV. interface fort spécialisée, ISP oblige. Et le cabinet ne va pas forcément faire la chose lui-même, SRP oblige -- surtout si les services se multiplient. Obtenir l'interface de prise de RDV va nous faire passer par la secrétaire présente, ou une ASV chez le véto, ou le toubib s'il est seul, etc. Et on a l'impression que l'on viole Déméter.
    La difficulté avec cette loi est d'arriver à l'équilibre entre Déméter et SRP. Si on expose tous les services de tous nos composants via l'objet de haut niveau, on va avoir un soucis côté SRP. Effectivement, il va y avoir un moment où il va falloir admettre que le service est un objet complexe et que l'on demande accès à un service. Mais nommer "getSecrétaire()" ce service sera une fuite d'abstraction dans certains cas, et trop limitatif si cela doit évoluer.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  17. #137
    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
    En fait (bien que j'aie l'impression que Igor_ a décidé d'ignorer cette discussion), il serait peut-être temps de revenir aux fondamentaux les plus évidents en se posant la question essentielle : Pourquoi créer une agrégation de données (quel qu'en soit le type)

    La réponse à cette question est double :
    1. Pour permettre aux données agrégées de "travailler ensembles" et
    2. pour obtenir un type de donnée qui nous permette de faire bien plus que la somme de ses composants


    (en fait, je ne suis pas sur du tout qu'il y ait une si grande différence entre les deux raisons mais bon... )

    Vous voulez un exemple simple Pensez à une structure Coordinate2D ou à une structure Date : chaque composant n'est jamais qu'un type primitif "à définir selon nos besoins", éventuellement une énumération (qui n'est rien d'autre qu'une ensemble de valeurs numériques entières, ce qui revient au même), mais, grâce au fait qu'on fait travailler tous les composants ensembles, nous pouvons utiliser l'agrégation dans un domaine tout à fait différent de celui dans lequel nous aurions utilisé notre type primitif.

    Bon, d'accord, ces deux types ont sémantique de valeur, ce qui est encore "un peu particulier" par rapport au cas proposé par Igor_, mais le fait reste que l'on obtient quelque chose utilisable dans un référentiel (beaucoup) plus complexe que celui que l'on aurait pu utiliser... avec les trois composants pris séparément.

    Le fait est que la sémantique de valeur et la sémantique d'entité n'interviennent absolument pas à ce niveau. Elle définissent les propriétés intrinsèques que l'on peut s'attendre, mais elle ne changent absolument pas le but de la création d'une agrégation.

    Si bien que si l'on a -- pour reprendre l'exemple de Igo_ - une classe Savoir et une classe Comportement, le but en agrégeant une donnée de chaque type n'est pas "simplement" de disposer d'un type de donnée qui reprenne les services proposés par la classe Savoir et par la classe Comportement à son compte : le but est de disposer d'un type de donnée qui fournisse des comportements ayant recours aux services proposés par (prafois l'une de ces données, parfois l'autre, parfois) les deux données prises ensemble pour déterminer la logique à mettre en oeuvre.

    Il arrive en effet parfois que l'un des services dont on s'attend à disposer de la part de la classe utilisatrice ne soit rien d'autre... qu'un service tout droit issu de l'une des données agrégées, mais, dans la plupart des cas, les services dont on s'attend à disposer utiliseront sans vergogne n'importe quel service proposé par n'importe quelle donnée agrégée dans... à peu près n'importe quelle combinaison.

    Cela sous entend que l'on peut très bien avoir accès "ailleurs" aux données de type Savoir ou aux données de type Comportements qui sont agrégées pour obtenir notre type Agent, et que nous pouvons donc -- en cas de besoin, mais en respectant certaines restrictions -- y avoir recours "séparément".

    On peut même parfaitement envisager -- si besoin -- d'avoir accès au même instant aux données de type Savoir et aux données de type Comportement s'il se fait que l'on a besoins des services fournis par ces deux types mais que leur utilisation n'entre pas dans le cadre des attributions de la classe Agent.

    Quoi qu'il en soit, si on décide de créer une classe d'agrégation et de se contenter d'exposer les différents services proposés par les données agrégées, cela n'a pas beaucoup de sens, entre autres parce que cela viole le SRP et l'ISP.

    aussi, quand tu dis
    Citation Envoyé par igor_ Voir le message

    Mais peut-être qu'en inversant le sens de ma démonstration, ces deux points te sembleront plus clairs :

    Situation 1 :
    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
     
    class Agent
    {
    public:
       string nom() const { return m_nom; }
       string affiche() const;
     
       void demarre() { m_comportement.demarre(); }
       void arrete() { m_comportement.arrete(); }
       string descriptionComportement() const { return m_comportement.description(); }
     
       bool connait(const Fait & fait) const { return m_savoir.connait(fait); }
       bool peutDeduire(const Fait & fait) const { return m_savoir.peutDeduire(fait); }
     
    private:
       Comportement m_comportement;
       Savoir m_savoir;
       string m_nom;
    };
    Je dis : mauvaise compréhension de la notion de service : celui qui va utiliser ta classe Agent se fout pas mal de savoir ce que l'agent connait, la description du comportement qu'il va manipuler en interne ou ce qu'il peut déduire d'une donnée quelconque! Il va invoquer un service spécifique à la classe Agent (obéit ) en lui fournissant toutes les données qui sont nécessaires pour que l'Agent puisse "prendre ses propres décisions", par exemple sous une forme qui serait proche de
    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
     
    class Agent
    {
    public:
       string nom() const { return m_nom; }
       string affiche() const;
       void reagis(Fait const & fait){
           /* tu vois, quand je parle de "n'importe quelle combinaison cohérente" */
           if (!(m_savoir.connait(fait)  || m_savoir peutDeduire(fait))){
               m_savoir.apprend(fait);
           }
           m_comportement. demarre();
        }
    private:
       Comportement m_comportement;
       Savoir m_savoir;
       string m_nom;
    };
    De cette manière on peut tout à fait s'en foutre de savoir si les classes Savoir ou Comportement sont des classes abstraites, des abstractions ou des types de données réels : on utilise directement les services qu'elles exposent pour permettre à la classe Agent de fournir un service qui est bien plus que l'ensemble des services proposés par Savoir et par Comportement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Ou, pour faire encore plus simple : le code
    Luc.getComportement().demarre();
    Luc.affiche();
    gereObstacles(Luc.getComportement());     // n'utilise que Agent::arrete
    afficheConnaissances(Luc.getSavoir());       // n'utilise que Agent::connait et Agent::peutDeduire
    devrait non pas se trouver dans une fonction libre quelconque, ni même dans la fonction membre d'une quelconque autre classe utilisatrice de la classe Agent, mais... dans une fonction membre de la classe Agent "himself" (avec les modifications requises pour que cela fonctionne, bien sur )

    Alors, bien sur, il faut aussi veiller à ne pas trop malmener le DIP. Mais, si tu crées une classe qui doit permettre d'appliquer DIP à ta classe Agent, cette classe ne devra, de toutes manières, dépendre de rien d'autre que des services (plus ou moins exposés, selon le cas) par ta classe Agent.

    Si bien que si tu veux -- ailleurs dans ton code -- appliquer DIP sur des données de type Savoir ou sur des données de type Comportement, il faudra encore une fois veiller à ce que les données de ces deux types utilisées par les différentes instances de la classe Agent soient ... accessibles par "un autre chemin" (un "gestionnaire" -- dieux que je n'aime pas ce terme -- quelconque )
    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. #138
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 068
    Points : 12 111
    Points
    12 111
    Par défaut
    Ce "débat" sur les objets composites me fait penser à la solution proposer par COM.
    Solution qui permettait d'avoir des objets sachant qu'ils font partie d'un "ensemble" et de pouvoir déléguer tout ou partie des fonctionnalités vers cet ensemble.
    Ensemble qui lui-même pouvait demander à d'autres éléments de cette ensemble de faire les actions nécessaires.
    C'est une approche plus composant que purement objet.

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