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

C++ Discussion :

La programmation en C++ est difficile, le génie logiciel en C++ est encore plus difficile


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2023
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2023
    Messages : 1
    Points : 10
    Points
    10
    Par défaut La programmation en C++ est difficile, le génie logiciel en C++ est encore plus difficile
    La programmation en C++ est difficile, le génie logiciel en C++ est encore plus difficile

    EDUARDO ROCHA 26-06-2023 Génie logiciel
    Mis à jour le 6 juillet 2023.
    Il existe probablement une corrélation entre les compétences en programmation C++ d’une personne donnée et sa capacité à développer des logiciels dans ce langage. Cependant, ces deux aspects sont distincts et n'évoluent pas toujours ensemble. Il est naturel de supposer que la maîtrise de C​++ se traduit directement par la capacité de développer des logiciels en C​++, mais les deux ne sont pas toujours synonymes. Cet article explique comment la complexité du C​++ crée des défis pour le génie logiciel. Il traite également de l'importance de la simplicité pour la maintenabilité et le succès à long terme.

    Le génie logiciel et la programmation ne sont pas la même chose.
    « Le génie logiciel peut être considéré comme une "programmation intégrée au fil du temps". »
    _ Génie logiciel chez Google

    C++ est complexe, le génie logiciel n’aime pas ça

    C++ est un cas particulier en raison de sa complexité. Il offre de nombreuses façons d'accomplir la même chose et il comporte également de nombreux pièges. C++ est un langage si puissant que les développeurs ont mis au point une infinité de modèles de programmation. Toutefois, le génie logiciel n'aime pas la complexité et ne s'entend pas naturellement avec le C++. Peut-être que cela n'est pas visible dans les petits projets ou les équipes, mais considérez les défis lorsque des dizaines, voire des centaines d'ingénieurs travaillent sur la même base de code comprenant des centaines de milliers de lignes.

    Tout comme C, C++ attend du développeur qu'il soit un expert et qu'il l'utilise avec soin. Se tirer une balle dans le pied est assez facile. Pour les projets à grande échelle avec plusieurs développeurs, où seulement quelques-uns seront des experts, le soin et l'attention de toutes les personnes impliquées sont indispensables.
    Par exemple, considérez les principes de génie logiciel suivants :

    1. «Vous n'en aurez pas besoin. » “You aren’t gonna need it” (YAGNI) stipule qu'un programmeur ne doit pas ajouter de fonctionnalités avant de les avoir jugées nécessaires. C++ propose de nombreuses manières différentes d’aller à l’encontre de ce principe. Il est tentant de faire d'une fonction ou d'une classe un modèle afin qu'il puisse être réutilisé pour différents types de données, même s'il est actuellement utilisé pour un seul type. Cela rend le code plus difficile à lire, augmente le temps de compilation et dégrade l'utilisation d'outils tels que les analyseurs statiques et les compléteurs de code. Par conséquent, cela ne devrait pas être fait à moins qu'il n'y ait un besoin pour cela.
    2. Évitez l'optimisation prématurée. C'est un principe bien connu qui peut être ignoré dans n'importe quel langage de programmation. Toutefois, si vous utilisez C++ dans un projet, c’est probablement parce que vous avez besoin de bonnes performances. Donc, un certain niveau d'optimisation est nécessaire ; parfois, il faudra même beaucoup d'optimisation. Le problème est qu'il est difficile de délimiter, au sein d'un projet, le code qui doit être optimisé et le code qui n’en aura pas besoin. C++ nous donne les outils pour tout optimiser et nous optimisons souvent plus que nécessaire.


    J'adore C++ et c'est mon langage de prédilection par défaut. S'il est utilisé correctement, il fera au moins aussi bien que la plupart des autres langages. Cependant, reconnaître les dangers et les pièges potentiels du langage est la première étape vers un développement sain.

    La simplicité est la clé d'une bonne ingénierie logicielle et C++ par défaut n'est pas simple.

    Simplifiez lorsque cela est possible !

    Le parcours d'apprentissage de C++ a souvent plusieurs pics de confiance. Plus vous apprenez, plus vous réalisez à quel point vous ne savez pas. Et je crois que cela crée un modèle intéressant. Les développeurs expérimentés ont tendance à se limiter à des sous-ensembles du langage et à des sous-ensembles de modèles de programmation suffisants et sûrs. Cette approche est efficace pour simplifier le langage pour un développement facile et maintenable.
    Je ne fournirai pas de recette pour le faire. Je ne suis pas sûr d'être qualifié pour le faire. Une chose que je peux dire, c'est qu'un code simple est généralement meilleur que le code optimal et le plus performant. En C++, le code optimal est souvent difficile à lire, difficile à comprendre et, surtout, difficile à maintenir. Je dirais qu'une grande partie de la programmation C++ peut être décrite comme une optimisation précoce à petite échelle.

    Un autre problème est que l'écriture de code complexe peut être amusante et, parfois, belle. De nombreux développeurs tombent amoureux de C++ pour cela. Beaucoup d'entre nous trouveront de la joie en utilisant des motifs complexes pour le plaisir. Néanmoins, le problème est que le code devient souvent plus compliqué qu'il ne devrait l'être. Moi-même, j'en suis coupable. Les développeurs qui entrent dans ce groupe devraient au moins être conscients de ce qu'ils font afin qu'ils puissent réfléchir à deux fois avant de trop compliquer les choses pour le plaisir. J'ai travaillé avec des gens qui s'intègrent très bien dans ce groupe, mais qui ne le savent pas. Beaucoup perçoivent l'ajout d'une complexité inutile comme une démonstration de compétence et ne voient pas ses inconvénients (ou ne s'en soucient tout simplement pas).


    « Le débogage est deux fois plus difficile que l'écriture du code. Par conséquent, si vous écrivez le code aussi intelligemment que possible, vous n'êtes, par définition, pas assez intelligent pour le déboguer.
    — Brian Kernighan

    Si la simplification n'est pas possible, encapsulez les bits complexes

    Si vous utilisez C++, c’est probablement parce votre projet nécessite de bonnes performances. En outre, des modèles de conception plus complexes peuvent être nécessaires ou peuvent entraîner un code plus simple. Dans ces cas, C++ fournira les bons outils pour le travail, mais le code résultant peut ne pas être facilement lisible ou facile à lire ou à comprendre.

    Heureusement, C++ fournit également les outils pour encapsuler correctement et cacher cette complexité. Ici, suivre les principes de l'ingénierie logicielle comme SOLID avec une attention et un soin supplémentaires peut guider le développeur vers le succès.

    Le temps supplémentaire nécessaire pour le faire correctement pour les pans les plus complexes (par exemple, une conception plus approfondie et des révisions de code) en vaut la peine à long terme.

    Principaux points à retenir

    1. C++ est connu pour sa grande complexité et offre de nombreux modèles de programmation. Cependant, le génie logiciel, qui met l'accent sur la simplicité et la maintenabilité, peut ne pas s'aligner facilement avec les subtilités du C++.
    2. Simplifiez C++ pour un développement maintenable. L'écriture de code facile à comprendre et à maintenir est généralement plus précieuse pour le succès à long terme que l'écriture de code optimal et allégé.
    3. Soyez conscient de la complication excessive et de l'optimisation précoce. Tenez-vous et vos collègues responsables.


    La prochaine fois que vous interviewerez quelqu'un pour un poste senior en C++, ne demandez pas au candidat à quel point il est bon en C++, posez-lui des questions sur les pièges du C++ pour le génie logiciel. Il sera très facile d'identifier des ingénieurs ayant une expérience de développement pertinente.

    Faire ce qui précède est plus facile à dire qu'à faire. Parfois, des modèles de programmation complexes avec des fonctionnalités de langage complexes se traduiront par un code plus simple et meilleur. Apprendre à le faire nécessite non seulement de l'expérience, mais aussi de la sensibilisation. J'espère que ce billet augmentera votre sensibilisation.

    Je tiens à souligner que cet article a été écrit sur la base de mes propres fortes opinions. Donc, si vous êtes d'accord ou si vous avez un point de vue différent, j'aimerais l'entendre ! N'hésitez pas à laisser un commentaire ou à nous contacter.

    La version originale de cet article

    Et vous ?

    Que pensez-vous de la programmation en C++ ?
    Pensez-vous que la programmation en C++ est vraiment difficile ? Partagez vos avis.

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 354
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 354
    Points : 1 419
    Points
    1 419
    Par défaut que de vieux souvenirs
    J'ai vraiment aimé le c++, j'ai commencé dans ce language. Je me suis même éclaté, j'avais tout fait entièrement.

    La conception logiciel est la clef de tout développement, et elle est plus dure en C++ car il faut définir qui est le propriétaire de chaque objet (Cependant, même si les gens ne le font pas en java ou c#, c'est un méga tort, et fait du code peu fiable.) et définir une bonne API est une chose complexe, mais dans tous les languages.

    Après je pense que la difficulté ultime est la reprise du code par quelqu'un d'autre. Ma dernière expérience était en C# et était tout bonnement horrible, cependant il est assez aisé de faire du refactoring en C#.

    J'avoue que je me suis dit, tellement j'ai souffert, qu'au vu de ce que des personnes peuvent faire en C#, je n'imagine pas ce qu'ils peuvent faire en C++. Aurais-je réussi à modifier et faire évoluer le programme ? je n'en suis pas sûr car le code est 10x plus difficile à lire, mais aussi 10x plus difficile à refactorer en C++.

    Je ne sais pas si je reviendrais un jour à programmer en C++, je ferais surement un audit du code avant de me décider 🫣

    ps: à tous les managers et DSI : vous êtes responsable de la situation dans laquelle vous avez mis vos équipes, être dans le déni ne sert à rien, la réalité reviendra toujours au plus mauvais moment avec des conséquences toujours plus grandes.

  3. #3
    Membre extrêmement actif
    Avatar de Madmac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    1 687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 687
    Points : 1 382
    Points
    1 382
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par epsilon68 Voir le message

    Je ne sais pas si je reviendrais un jour à programmer en C++, je ferais surement un audit du code avant de me décider 🫣

  4. #4
    Membre extrêmement actif
    Avatar de Madmac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    1 687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 687
    Points : 1 382
    Points
    1 382
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par Eduardo Rocha Voir le message
    1. «Vous n'en aurez pas besoin. » “You aren’t gonna need it” (YAGNI) stipule qu'un programmeur ne doit pas ajouter de fonctionnalités avant de les avoir jugées nécessaires. C++ propose de nombreuses manières différentes d’aller à l’encontre de ce principe. Il est tentant de faire d'une fonction ou d'une classe un modèle afin qu'il puisse être réutilisé pour différents types de données, même s'il est actuellement utilisé pour un seul type. Cela rend le code plus difficile à lire, augmente le temps de compilation et dégrade l'utilisation d'outils tels que les analyseurs statiques et les compléteurs de code. Par conséquent, cela ne devrait pas être fait à moins qu'il n'y ait un besoin pour cela.
    2. Évitez l'optimisation prématurée. C'est un principe bien connu qui peut être ignoré dans n'importe quel langage de programmation. Toutefois, si vous utilisez C++ dans un projet, c’est probablement parce que vous avez besoin de bonnes performances. Donc, un certain niveau d'optimisation est nécessaire ; parfois, il faudra même beaucoup d'optimisation. Le problème est qu'il est difficile de délimiter, au sein d'un projet, le code qui doit être optimisé et le code qui n’en aura pas besoin. C++ nous donne les outils pour tout optimiser et nous optimisons souvent plus que nécessaire.

    Le deuxième paragraphe est valable, mais pas le premier. La vitesse de compilations n'est pas un argument valable. La vitesse du code est la seule chose qui compte quand il est question de compilation. Un général, les programmeurs d'expérience font ce genre de truc en sachant que cette classe aura des descendants. Ou pour éviter de fabriquer des constantes et variables globales Et parce que cela permet de définir les noms des méthodes et de variables, à l'avance, afin encadrer les programmeurs qui travailleront avec ce code.

    Citation Envoyé par Eduardo Rocha Voir le message

    Si vous utilisez C++, c’est probablement parce votre projet nécessite de bonnes performances. En outre, des modèles de conception plus complexes peuvent être nécessaires ou peuvent entraîner un code plus simple. Dans ces cas, C++ fournira les bons outils pour le travail, mais le code résultant peut ne pas être facilement lisible ou facile à lire ou à comprendre.

    Heureusement, C++ fournit également les outils pour encapsuler correctement et cacher cette complexité. Ici, suivre les principes de l'ingénierie logicielle comme SOLID avec une attention et un soin supplémentaires peut guider le développeur vers le succès.
    La POO a été inventer avant tout pour produire du code avec des groupes de programmeurs. Si la vitesse est votre premier soucie, SOLID est à éviter comme la peste. Il est difficile à optimiser. Et DRY est encore pire. La POO a la réputation de produire des programmes lents alors qu'en réalité la cause principale est l'adoption de SOLID. SOLID permet la PRODUCTION de code plus rapidement. POINT!.

    Mark Zuckerberg a fait la première version de Facebook en Ruby alors que le langage était trois fois plus lent. parce qu'il avait compris que la première qualité qu'un programme se doit d'avoir est de fonctionner.

    “Done is better than perfect.”
    -Mark Zuckerberg

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 193
    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 193
    Points : 17 161
    Points
    17 161
    Par défaut
    L'objectif de SOLID est de produire du code solide: résistant au passage du temps, au changement de développeurs, etc. On dit aussi "maintenable".
    Il permet de réduire les bugs (disparition totale de classes entières de bugs comme l'oubli de fermeture d'une session, d'une connexion, etc)

    Je n'ai jamais vu SOLID rendre un programme écrit en POO plus lent, moins optimisé. As-tu des témoignages, des études ou des exemples concrets la-dessus?
    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

  6. #6
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 743
    Points : 3 645
    Points
    3 645
    Par défaut
    Les principes SOLID ont une approche très OO dans leur description, mais en fait, ce n'est pas SOLID qui rend moins opti ou plus lent, mais la POO dans certains contextes.

    Par exemple, si on possède un tableau d'un type quelconque qui contient 3 états qu'on veut manipuler, on va généralement faire une boucle sur chaque élément qui manipule l'état 1, puis le 2, puis le 3. Si les calculs dépendent du résultat de l'état précédent, on va faire une boucle qui manipule l'état 1, puis une boucle pour l'état 2 et pareil pour le 3ème.

    Il s'avère que cette approche est généralement moins optimale que 3 tableaux qui représente chacun un état, car elle engendre plus de perte de cache. C'est la différente entre SoA (Structure of Array) et AoS (Array of Structure).

    À ce niveau, on s’intéresse plus aux valeurs que contiennent nos structures plutôt qu'à une abstraction qui permet de les manipuler de manière transparente. Dans ce contexte on se retrouve en opposition avec les principes SOLID. De toute manière, une approche OO ne fonctionne pas bien ici, on va plutôt faire de la programmation orientée data.

    Par contre, quand l'OO est adapté, SOLID est utile et je suis du même avis que toi sur la maintenabilité.

    Par contre, je ne vois en quoi SOLID permet la disparition totale des fermetures d'une connexion ? Pour moi c'est le RAII qui fait permet cela ou autre selon le langage (le mot clef finally, les contextes managés, etc)

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

    Informations professionnelles :
    Activité : aucun

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

    Humm, je ne suis pas aussi catégorique que toi..

    Il est vrai que le L de SOLID (LSP, mis pour Liskov Substitution Principle) est -- très clairement orienté objet, vu qu'il parle du seule principe qui soit effectivement spécifique à l'OO : la substituabilité.

    Mais pour les autres...

    Il n'y a -- par exemple -- absolument aucune difficulté à s'assurer qu'une fonction fasse une chose et une seule, même dans un contexte "non OO", que l'on adopte l'approche AOS ou SOA ne changera sans doute absolument rien : une fonction sera toujours plus facile à tester et à maintenir si elle ne s'occupe effectivement que d'une chose et d'une seule.

    Il en va d'ailleurs de même avec l'OCP : Il est "relativement facile" de s'arranger pour "fermer son code" aux modifications (eg : pour faire en sorte qu'un comportement écrit, testé et validé ne doive pas être modifié) mais pour "l'ouvrir" aux évolutions. Et dans ce cas encore, AOS ou SOA n'y changera rien ... à moins bien sur que l'on décide de passer de l'un à l'autre.

    Quant aux deux derniers -- ISP et DSP --j'ai d'avantage tendance à les considérer comme les pistes privilégiées à envisager pour améliorer le respect des trois premiers ou, selon la situation, comme le "résultat naturel" d'une tentative (réussie) d'améliorer le respect des trois premiers.

    Après, on peut bien sur discuter des heures sur "ce qui fait" réelleement "l'approche OO". M'étant déjà exprimé sur le sujet, je ne le ferai ici que si on m'en fait la demande Mais comme vous le savez, j'ai un avis "plutôt tranché" et sans doute très différents de la plupart des gens

    Mais, quoi qu'il en soit, il faut se souvenir que SOLID sont -- d'abord et avant tout -- des principes de conception, ce qui implique que l'on doit (ou du moins, que l'on devrait) s'assurer :
    1. que la manière dont on envisage de faire les choses les respecte les respecte avant d'écrire la moindre ligne de code et
    2. que la manière dont on écrit effectivement le code continue à les respecter "tout au long du processus"
    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

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 743
    Points : 3 645
    Points
    3 645
    Par défaut
    Il n'y a pas que L qui saute, il y a aussi le D et je ne vois pas vraiment comment appliquer l'ouverture du O sans point de variation disponible. Ça va être compliqué de faire des extensions sans faire de modification.

    Pour moi il n'y a que le S (et le I qui va bien avec) qui est un principe plutôt logique, mais qui possède certaines limites: plus on possède de contexte plus il est "facile" de trouver des optimisations. Par conséquent, 2 fonctions peuvent être fusionnées pour faire la même chose de manière plus efficace. Je ne vais pas dire que cela arrive souvent, c'est même plutôt rare, mais c'est quelque chose qui arrive un peu plus souvent quand on se concentre sur nos données.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Pour le D, on peut encore disucter, bien que, de manière générale, il s'appliquerait en SOA en transmettant de préférence la structure complète (ou, à défaut, l'un des tableau qui la compose) plutôt que la donnée spécifique que l'on trouve dans un tableau spécifique et qui nous intéresse "tout particulièrement".

    Car, quoi que l'on en dise, un tableau reste une abstraction, et une structure aussi

    Quant au O, ben, en fait, il vient main dans la main avec le S en SOA, dans le sens où, si chaque fonction ne fait qu'une et une seule chose, si tu veux faire évoluer une de tes structures de tableaux, tu vas sans doute rajouter un nouveau tableau à cette structure et ... les fonctions qui "vont bien" pour en gérer les données (dans le respect de SRP).

    Et, pour profiter de cette évolution, tu peux "simplement" créer ... une nouvelle fonction qui fait appel aux fonctions "complexes" existantes et qui intègrent les fonctions de base que tu viens d'ajouter pour l'évolution. Ce qui se fait dans le respect de l'OCP.

    Bien sur, nous sommes d'accord sur le fait qu'il puisse, peut-être (surement), parfois (souvent), sembler (être réellement) plus intéressant d'aller modifier les fonctions complexes existantes que d'aller créer une fonction séparée qui prenne l'évolution en charge... Mais ca, c'est la grosse tentation que l'on a de manière systématique, et c'est justement la raison pour laquelle l'OCP existe
    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. #10
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 743
    Points : 3 645
    Points
    3 645
    Par défaut
    Mhouais, ce n'est pas vraiment ce que j’appelle de l'OCP. Ce que tu me décris me fait plus penser à l'équivalent d'une nouvelle classe sans parenté. Pour moi, l'OCP est la capacité à faire des points de variation -> du polymorphisme. La majorité du temps, quand on fait des points de variation sur des données, on se retrouve à modifier du code existant, ce qui ne respecte pas l'OCP. Exemple bête, les visiteurs / std::variant.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Pour moi, l'OCP est la capacité à faire des points de variation -> du polymorphisme
    L'OCP est un principe (de conception), le polymorphisme est un concept (de programmation) ...

    Tu fais simplement l'erreur de placer la relation entre le principe et le concept dans le mauvais sens : l'OCP c'est "l'objectif à atteindre", la règle qu'il faut s'arranger pour respecter, le polymorphisme c'est le moyen (en fait l'un des moyens) qui nous est donné pour y arriver...

    Cependant, le polymorphisme n'est pas -- loin s'en faut -- le seul moyen qui nous permettra de respecter l'O.

    Car l'OCP nous dit simplement que
    le code doit être fermé aux modification, mais ouvert aux évolutions"
    Autrement dit, tu ne dois pas (ou, du moins, tu ne devrais pas) avoir à modifier un code existant -- qui a été testé et validé -- (c'est l'aspect "fermé aux modifications") afin d'être en mesure d'intégrer une évolution (c'est l'aspect "ouvert aux évolutions")

    Ou, si tu préfères, tout ce que te demande en réalité l'OCP, c'est de faire en sorte (ou du moins d'essayer) que le code que tu as écrit avant-hier et validé hier ne devra pas modifié demain pour te permettre d'intégrer l'évolution suivante.

    Peu importe comment tu y arrives !!!

    Au mieux, il est possible de déconseiller certaines pratiques, comme le RAII (if (dynamic_cast< ... *>(ptr)!= nullptr ) ou un équivalent à peine caché sous forme d'un switch ... case (ou n'importe quel switch case dont on aurait de bonnes raisons de croire que le nombre de valeurs envisagées risque d'augmenter à chaque évolution)


    Et, de ce point de vue là, le SRP te donne "une autre clé" nous permettant d'assurer le respect de l'OCP; même si c'est de manière un peu plus indirecte

    Car, mieux le SRP sera respecté, plus tu pourras partir du principe que les fonctions qui le respectent le mieux seront celles qui... auront le moins besoin dêtre modifiées pour permettre "l'évolution suivante".

    Tu n'as même pas besoin d'être dans une approche orientée objets ... Tu as juste besoin de te rendre compte que ta fonction "super complexe" (ou peut être pas tant que cela) prend en réalité en charge "un certain nombre" de responsabilités qui auraient parfaitement pu être "ventilées" vers des fonctions "beaucoup plus simples"

    D'ailleurs, je vais même aller (beaucoup) plus loin : à part LSP, qui est vraiment très spécifique, et peut être l'ISP qui, à un certain niveau, ne pourra que t'inciter à ne pas *** forcément *** exposer toutes les fonctions que tu as créées, les trois autres principes (SRP, OCP et DIP) se tiennent pour ainsi dire par la main! Laisses moi m'expliquer avant de hurler, s'il te plait

    Le SRP t'incite à créer des fonctions qui n'ont qu'une et une seule responsabilité. Soit ...

    On pourrait donc croire qu'une fonction de tri ne prend qu'une seule et unique responsabilité : celle de ... trier les éléments qui lui sont donnés. On est d'accord

    Ben, en fait ... non, je ne suis pas "tout à fait d'accord" car -- je l'admets, je coupes les cheveux en quatre -- pour pouvoir décider de déplacer les éléments, il faut -- d'abord et avant tout -- qu'elle les compare deux à deux. Et cette comparaison est une responsabilité qui mériterait, selon les termes du SRP, d'être prise en charge par une fonciton spécifique.

    Le mieux de l'histoire, c'est que si tu "extrait" effectivement cette fonction de comparaison de ton algorithme de tri, ta fonction de tri n'a ... plus aucune raison d'être modifiée une fois qu'elle a été validée (à moins, bien sur, que tu décide de changer d'algorithme de tri ) Voilà donc l'OCP qui se pointe "tout naturellement" car, que tu veuilles un tri "croissant" ou "décroissant", il n'y a finalement plus que ... la manière dont la comparaison sera effectuée qui devra être modifiée si tu veux passer de l'un à l'autre.

    Au pire, tout ce qu'il te reste à faire, c'est de permettre à la personne qui veut utiliser la méthode de tri que tu as développée de choisir la fonction de comparaison qui lui convient (et, pourquoi pas, d'en sélectionner une "par défaut", pour la facilité).

    Et si, au lieu de parler de "fonction de comparaison", nous venions parler de "comparateur" Il s'agirait toujours de la même "fonction de comparaison", cependant, le simple fait de lui avoir choisi un autre terme qui "puisse sembler plus adapté" pour la désigner, et ... Bardaf : nous voilà avec un "zolie abstraction".

    Et devine quoi Si je décide de faire dépendre ma fonction de tri de l'abstraction (désormais) connue sous le nom de "comparateur", voilà le respect du DIP qui arrive en courant !

    Car, à partir du moment où tu est -- effectivement -- en mesure de fournir deux éléments à ton "comparateur" et qu'il te permet de déterminer la relation A <comparaison> B est valide, il peut parfaitement te servir dans ta fonction de tri. Et ce, quelle que soit la forme effective de ton "comparateur", pour autant que nous nous soyons mis d'accord sur la manière de l'utiliser

    Il est aussi vrai qu'il serait sans doute particulièrement intéressant d'aborder une approche générique dans le cadre de cet exemple. Et pourtant, la logique de SRP appelant OCP et DIP dans la foulée est susceptible de s'appliquer ... quel que soit le paradigme envisagé

    La majorité du temps, quand on fait des points de variation sur des données, on se retrouve à modifier du code existant, ce qui ne respecte pas l'OCP. Exemple bête, les visiteurs / std::variant.
    Peut-être est-ce l'occasion, ici, au calme du forum, d'essayer d'analyser les raison qui rendent cette situation possible, et, si possible, de dresser des pistes à envisager afin de l'éviter.

    Bien sur, il sera surement beaucoup plus facile de suivre ces pistes sur un code de 100 fichiers que sur un code de 100 000 ... A moins que tu n'aies du temps à perdre dans une refactorisation complète
    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

  12. #12
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 743
    Points : 3 645
    Points
    3 645
    Par défaut
    Tu t'es vachement centrés sur la programmation générique. Dans ce que tu décris, le Comparator revient à une interface avec post et pré-conditions, LSP a toute sa place. Ce dont je parle est un système où chaque type à son/ses propres algos (exit la généricité), voir des interdépendances. Du coup je reste sur ma position, l'OCP n'est pas le bienvenu.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Tu t'es vachement centrés sur la programmation générique.
    Même pas...

    Il faut juste garder en tête qu'une fonction n'est ... que le moyen de faire comprendre à quelque chose d'aussi bête qu'un oridanteur le comportement que l'on attend de lui à un moment précis.

    Et il faut donc garder en tête le fait que ce comportement est destiné à nous fournir un résultat "clairement défini", "prédictible" et "reproductible":
    • clairement défini : C'est ce que l'on a le plus facile à obtenir, pour autant que l'on choisisse correctement le nom de la fonction... Il vaut mieux choisir un nom qui évoque clairement ce que la fonction est sensée faire
    • prédictible : Même si cela doit te demander "un certain temps" de le faire "à la main", tu es (ou devrais être) en mesure de déterminer à l'avance le résultat que tu obtiendra en appelant ce comportement (cette fonction) avec un jeu de donné spécifique (et dans une situation donnée)
    • reproductible : si tu appelles deux fois le même comportement avec les même données (et dans les même circonstances) tu obtiendra deux fois le même résultat.


    Et, à partir de là, on peut partir sur le SRP: une fonction ne devrait faire qu'une et une seule chose pour s'assurer de la faire bien

    C'est à dire que, si une fonction doit faire deux chose (comme "comparer" et "réarranger" pour reprendre mon exemple précédent), c'est -- peut-être -- qu'elle en fait une de trop. Tu devrais (pourrais) donc envisager "d'extraire" le comportement qui consiste à comparer deux éléments de celui qui consiste à les réarranger.

    Alors, bien sur, ce qui nous intéressant dans le comportement de comparaison, c'est le résultat que l'on obtient, et il faut donc ... un moyen de l'obtenir; mais c'est le propre de tout comportement, de toutes fonctions, non

    Et il semble "logique" de se dire que, ayant extrait le comportement "plus simple" qui consite à effectuer la comparaison de la fonction de "réarrangement", il faudra trouver un moyen -- n'importe lequel (fusse un pointeur de fonction) -- de faire en sorte que le comportement de réarrangement "sache" quel comportement de comparaison appeler et, surtout, comment l'utiliser : quelles données lui transmettre, dans quel ordre, et comment interpréter le résultat.

    L'abstraction n'arrivant que ... parce que je décide d'appeler ce comportement de comparaison "compare", "comparator" ou encore "compareFunction" car je trouve cela plus clair que de l'appeler simplement "ptr" (ou "funcptr").
    Dans ce que tu décris, le Comparator revient à une interface avec post et pré-conditions,
    Mais toute fonction testable a interface (comment l'utiliser) , précondition (sur les données à transmettre) et postconditions (résultat escompté) ... Ou à tout le moins l'un ou plusieurs de ces éléments
    • Le simple fait de typer un paramètre va -- forcément -- imposer une précondtion car, si ce n'est pas le type adéquat (ou, au pire, si on ne sait pas convertir la donnée fournie dans le type adéquat), tu es dans la merde...
    • La moindre vérification de validité du résultat à l'intérieur de la fonction n'est jamais qu'une manière de t'assurer du respect d'une post condition
    • Et l'interface ne fait jamais qu'exposer la manière dont tu vas l'utiliser : créer un pointeur de fonction qui renvoie une donnée d'un type donné à partir de deux données de type potentiellement identiques, c'est fournir une interface

    LSP a toute sa place.
    AAAhhh, non ... Du moins, pas dans le cadre de cette discussion ...

    Le LSP ne s'intéresse qu'aux notions de "sous-typage" (faisons simple : d'héritage / implémentation des interface) et de substituabilité. C'est d'ailleurs la raison de la présence du S que l'on trouve entre principe et Liskov

    La substituabilité étant la possibilité de manipuler un objet de type B -- qui serait "sous-type de A" comme s'il s'agissait en réalité d'un objet du type A.

    Pré et post conditions (ainsi qu'invariant) étant des notions intervenant dans la programmation par contrat. Si tu me donnes des données valides et cohérentes (préconditions), je dois pouvoir te fournir un résultat valide, cohérent, prédictible et reproductible (post conditions) ...

    Ce qui se passe, c'est que tu confonds encore une fois le "quoi" et le "comment" : le "quoi" étant la substituabilité, et le comment étant -- entre autres -- composé de la programmation par contrat, celle-ci ne faisant que te donner "des pistes à suivre" pour obtenir une substituabilité cohérente
    Ce dont je parle est un système où chaque type à son/ses propres algos (exit la généricité)
    Je viens de t'expliquer que la généricité n'est pas une fin en soi, mais, à partir du moment où elle peut arriver "naturellement" ... simplement parce que tu as respecté le SRP, une fois qu'elle est possible (ou facilitée), il serait peut-être dommage de ne pas en profité en cas de besoins
    voir des interdépendances.
    Ahh, les interdépendances ...

    Quelles qu'elles soient, c'est toujours un gros problème. Et le truc, c'est qu'il s'agit d'une boulle à facette, façon "soirée disco"...

    Car certaines viennent carrément d'une mauvaise conception au départ. Et d'autres viennet aussi parfois de la manière dont le code est écrit. Le pire étant qu'il y a tellement moyen d'en obtenir pour si peu de moyens de les éviter que cela peut devenir une gagure que d'essayer de les éviter

    Ceci dit, je suis sur que tu penses spécifiquement à un cas bien particulier auquel tu auras été confronté "récemment".

    Ceci dit, interdépendances et OCP ne sont que les deux face d'une même pièce, dans le sens où, plus tu as d'interdépendances, moins il t'es aisé de respecter l'OCP et, à l'inverse, plus tu respecte l'OCP, moins tu as de risque de souffrir d'interdépendance "fortes"
    Du coup je reste sur ma position, l'OCP n'est pas le bienvenu.
    C'est ton choix

    Et je vais laisser les autres faire le leur ...

    Pour ma part, j'aime simplement trop écrire sur un forum, et je me laisse beaucoup trop facilement emporter par ma plume
    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. #14
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 743
    Points : 3 645
    Points
    3 645
    Par défaut
    Citation Envoyé par koala01 Voir le message
    AAAhhh, non ... Du moins, pas dans le cadre de cette discussion ...

    Le LSP ne s'intéresse qu'aux notions de "sous-typage" (faisons simple : d'héritage / implémentation des interfaces) et de substituabilité. C'est d'ailleurs la raison de la présence du S que l'on trouve entre principe et Liskov

    La substituabilité étant la possibilité de manipuler un objet de type B -- qui serait "sous-type de A" comme s'il s'agissait en réalité d'un objet du type A.

    Pré et post conditions (ainsi qu'invariant) étant des notions intervenant dans la programmation par contrat. Si tu me donnes des données valides et cohérentes (préconditions), je dois pouvoir te fournir un résultat valide, cohérent, prédictible et reproductible (post conditions) ...
    Je vais la faire à l'envers. Comporator décrit un type pouvant être décrit par une interface ou un concept. Tout type correspondant au concept de Comparator étant d'office un sous-type de Comparator. Sous-type ayant comme pré-condition une fonction équivalent à operator()(T const&, T const&) qui a comme post-condition un type convertible en bool. C'est de ce contrat que je parle. Tu remarqueras que je traite les types de la même manière que les valeurs, par conséquent, contravariance et covariance ne sont que pré et post-conditions. Mais comme de toute manière la notions de sous-typage peut être implicite quand basé sur le comportement (comprendre truc et bidule sont définit, hop, ça en fait un sous type de X: duck-typing) et que la substituabilité implique le respect d'un contrat, je ne me prive pas de réduire le concept à des pré et post-conditions.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    Je vais la faire à l'envers. Comporator décrit un type pouvant être décrit par une interface ou un concept. Tout type correspondant au concept de Comparator étant d'office un sous-type de Comparator. Sous-type ayant comme pré-condition une fonction équivalent à operator()(T const&, T const&) qui a comme post-condition un type convertible en bool. C'est de ce contrat que je parle.
    Ca, c'est parce que tu as spécifiquement choisi une approche orientée objet.

    Mais la programmation par contrat peut s'appliquer dés que tu te trouve face à un comportement dont tu veux garantir la "bonne exécution"

    Si tu veux développer une fonction "racineCaree", par exemple. Il faut que les entrées respectent deux pré-conditions:
    1. elles doivent représenter une valeur numérique
    2. elles la valeur numérique doit être strictement positive

    Et le résultat obtenu doit respecter une post-condition : si tu multiplie le résultat par lui-même tu dois obtenir la valeur fournie en entrée.

    C'est aussi de la programmation par contrat... Il n'y a pourtant absolument rien qui pourrais te faire penser qu'elle ait été utilisée dans une approche orientée objet

    Comparator n'est qu'une abstraction, qu'un terme que l'on va utiliser pour désigner "aussi précisément que possible" le genre de comportement que l'on est en droit d'attendre de sa part. Car on espère qu'il ne fera pas le café

    Si tu bloques sur le terme "comparator", appelle le COMPARE_FUNCTION pour insister d'avantage sur le fait qu'il s'agit d'une fonction (ou plus vraisemblablement d'un pointeur de fonction), ca me va très bien

    Et si tu as une meilleure idée de nom pour cette abstraction, vas-y, lache toi, fais toi plaisir

    Le truc, c'est que l'on est "tellement habitué" à utiliser la programmation par contrat dans le contexte d'une approche orientée objets qu'on finit par ne même plus se rendre compte qu'elle peut tout aussi bien l'utiliser dans des contextes différents.

    Mais comme de toute manière la notions de sous-typage peut être implicite quand basé sur le comportement (comprendre truc et bidule sont définit, hop, ça en fait un sous type de X: duck-typing) et que la substituabilité implique le respect d'un contrat, je ne me prive pas de réduire le concept à des pré et post-conditions.
    Tout à fait ...

    Il me semble d'ailleurs que Liskov avait à l'origine énoncé son principe dans une apporche fondamentalement fonctionnelle

    Et, du coup, je me demande pourquoi tu voudrais absolument forcer Comparator -- bien que le terme ait sans doute été mal choisi et que tu aurais sans doute préfré "COMPARE_FUNCTION" -- à rentrer dans le carcan Orienté Objets, alors qu'il s'agit simplement de ... la description intelligible d'un comportement prenant deux entrées et te renvoyant une valeur booléenne indiquant si la relation entre les entrée correspond à celle que l'on recherche.

    Car, ce que tu me dis, en substance, c'est:
    Je file une valeur X et une valeur Y à un comportement, et, au sein de ce comportement, X et Y forment une coordonnée

    Si je donne deux valeur de X et deux valeurs de Y à un autre comportement, il manipule deux coordonnées
    (je simplifie, hein )

    C'est cool ... Cette notion de "coordonnée" n'est en fait qu'un abstraction "de type" (comprends : qui défini la représentation des données et la manière de les interpréter), qui mériterait peut-être (ou pas du tout) d'apparaitre clairement dans ton code

    Vas donc "un peu plus loin" dans le fait de créer tes abstractions en créant ... des abstraction "comportementales". Comprends : si deux comportements prennent des entrées équivalentes et fournissent un résultat équivalent; je peux les regrouper au sein d'une abstraction désignant le "l'objectif général" de ce comportement.

    Peu importe la forme que cette abstraction "comportementale" prendra dans ton code.

    Peu importe le nom que tu lui donneras, pour autant qu'il ne laisse aucun doute sur l'objectif de la fonction : si Comparator te fait trop penser à l'approche orientée objets telle que vue par le C++, appelle cette abstraction COMPARE_FUNCTION si tu le souhaites

    Peu importe la manière dont tu t'y prendra pour l'adapter aux différents types de données que tu manipule : Peut-être une approche basée sur les politiques et les traits serait-elle intéressante à envisager ?

    Tout cela relève du domaine de l'implémentation. Et cela n'a rien à voir avec l'abstraction qui relève du domaine conceptuel.

    L'important étant que, ayant respecté le SRP (à l'exces, vas tu peut-être penser), tu te donnes l'opportunité en période de conception de "voir émerger" de nouvelles abstractions qui seront en mesure de te faciliter la vie lorsqu'il sera question de respecter l'OCP.
    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

  16. #16
    Membre extrêmement actif
    Avatar de Madmac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    1 687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 687
    Points : 1 382
    Points
    1 382
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par ternel Voir le message
    L'objectif de SOLID est de produire du code solide: résistant au passage du temps, au changement de développeurs, etc. On dit aussi "maintenable".
    Il permet de réduire les bugs (disparition totale de classes entières de bugs comme l'oubli de fermeture d'une session, d'une connexion, etc)
    Ce que tu que tu décris sont les avantages d'un framework qui utilise l'héritage. Mais ce soucier de SOLID avant même d'avoir une idée claire du résultat final amène les même risques que les microservices. SOLID devrait être considéré au même moment que le l'on passer à l'étape de l'optimisation

    Citation Envoyé par ternel Voir le message
    Je n'ai jamais vu SOLID rendre un programme écrit en POO plus lent, moins optimisé. As-tu des témoignages, des études ou des exemples concrets la-dessus?
    Le S de SOLID est le point le plus problématique. Si l'objet n'a qu'un type de responsabilité, cela exclus les conversion. Donc tu dois fabriquer des classes (et des objets additionnelles)pour gérer cette responsabilité. Alors que plusieurs constructeurs pourraient faire l'affaire.

    Et dans le cas des langages qui supportent les fonctions imbriqués, de grosses classes qui contiennent plusieurs objets sont parfaitement logique, car cela permet de remplacer des constantes globales en constante locale. Et de réduire le nombre de paramètre des certaines fonctions.

    Quelque fois utilisé une classe comme un domaine est la solution la plus performante. Plus on complexifie un programme, plus il devient difficile de l'optimiser. Donc avant de considérer SOLID, il est préférable de considérer Principe_KISS comme le critère le plus important.

  17. #17
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 193
    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 193
    Points : 17 161
    Points
    17 161
    Par défaut
    KISS est tout autant l'essence du SRP.

    J'applique SOID avec beaucoup d'intérêt sans avoir à définir le moindre héritage. J'ai même tendance à considérer l'héritage comme un problème (en tout cas, la virtualité et l'héritage publique)

    RAII, dont les smart-pointers, sont un excellent moyen de supprimer les fuites de mémoire. Démontrable, robuste, OCP à fond, et sans héritage.
    Une classe de connexion ssh aussi, toujours sans héritage.

    SOLID est pour moi une préoccupation pendant que je conçois mon architecture.
    C'est pour moi une application du principe d'encapsulation: si c'est fragile, je cloisonne et j'isole: SRP+OCP dans toutes les capsules. Pas d'héritage implique que L, I et D sont immédiatement respectés, puisque sans objet
    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

  18. #18
    Membre extrêmement actif
    Avatar de Madmac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    1 687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 687
    Points : 1 382
    Points
    1 382
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par ternel Voir le message
    KISS est tout autant l'essence du SRP.

    J'applique SOID avec beaucoup d'intérêt sans avoir à définir le moindre héritage. J'ai même tendance à considérer l'héritage comme un problème (en tout cas, la virtualité et l'héritage publique)
    L'héritage n'est pas forcément un problème. Mais s'il est utilisé sur une portion de code très utilisé (genre à l'intérieur d'une énorme boucle). Ou que le programme doit chercher une méthode sur plus d'une génération. Alors il est préférable de recopier les méthodes communes à tous ces classes.Le truc est de savoir, où l'héritage est susceptible de nos faire perdre de la vitesse.

    Les "smart pointers" ont les même handicaps que l'héritage. L'approche SOLID cohabite très avec les assemblages par composition (module en Ruby, Traits en Rust). En C++, c'est possible par l'inclusion d'une classe polymorphique avec idéalement un minimum de méthode. En terme de performance c'est le meilleur des mondes. Polymorphisme de l'héritage. Et la performance d'une fonction. Pourquoi? Parce que l'héritage n'est utilisé qu'à un seul endroit: Pendant la création de l'objet. Ce qui fait que le compilateur compile les méthodes de la même façon que des "fonctions amis".

Discussions similaires

  1. Réponses: 6
    Dernier message: 27/07/2022, 12h41
  2. Réponses: 0
    Dernier message: 07/10/2019, 14h35
  3. Réponses: 7
    Dernier message: 06/11/2017, 13h25
  4. Réponses: 14
    Dernier message: 12/06/2006, 00h10

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