SRP : Single Responsibility Principle
Une classe doit avoir une et une seule responsabilité
OCP : Open/Close Principle
Une entité doit être ouverte aux extensions et fermée aux modifications
LSP : Liskov Substitution Principle
Les sous-types doivent être interchangeables par leurs types de base
ISP : Interface Segregation Principle
Un client ne doit pas être forcé de dépendre de méthodes qu’il n’utilise pas
DIP : Dependency Inversion Principle
Il faut dépendre des abstractions, pas des implémentations
2. Définition
• SOLID est un acronyme qui désigne les 5 premiers principes de la
programmation orientée objet décrit par Robert Cecil Martin (Oncle
Bob)
• Il n’existe pas de hiérarchie dans ces principes
• Dans la pratique ces principes sont très imbriqués
3. 5 principes
• SRP : Single Responsibility Principle
Une classe doit avoir une et une seule responsabilité
• OCP : Open/Close Principle
Une entité doit être ouverte aux extensions et fermée aux modifications
• LSP : Liskov Substitution Principle
Les sous-types doivent être interchangeables par leurs types de base
• ISP : Interface Segregation Principle
Un client ne doit pas être forcé de dépendre de méthodes qu’il n’utilise pas
• DIP : Dependency Inversion Principle
Il faut dépendre des abstractions, pas des implémentations
4. Avant de commencer
• SOLID s’articule au cœur d’une architecture orienté objet, ses
principes sont un tremplin vers une certaine sérénité
• On peut considérer ces principes comme un « art de faire », de
bonnes pratiques
• « Principe », pas pattern. Si SOLID va nous dire ce qu’il faudrait faire,
les patterns vont nous dire comment le faire
• Utiliser ces principes demande de les conserver à l'esprit durant
chaque étape de nos développements
• Le pragmatisme doit rester maitre, une architecture trop complexe
peut en réalité nuire à ce pourquoi SOLID existe : la maintenabilité
6. SRP : Single Responsibility Principle
• Principe de responsabilité unique : une classe ne doit changer que
pour une seule raison
• Un moyen de trouver les raisons qui pourraient conduire la classe à
changer est d'analyser l'audience de la classe
SRP
7. SRP : Single Responsibility Principle
L’idée est que si une responsabilité évolue, alors on ne risque pas de
casser les autres pour avoir introduit des couplages forts comme du
code imbriqué le ferait.
• plus compréhensible car découpé, responsabilité par responsabilité
• testable plus facilement avec un spectre fonctionnel réduit
• plus facile à étendre
8. SRP : Single Responsibility Principle
Le respect excessif du principe d'unique responsabilité peut conduire à
de l'optimisation prématurée, une mauvaise conception et une
architecture qui se retrouve difficile à comprendre.
En revanche, les responsabilités techniques (non-métier), telles que la
persistance, les logs, l’accès aux données, etc. sont presque toujours à
scinder dès le début.
Ici, 2 responsabilités (gestion de la connexion
et de la communication) qui ne doivent pas
nécessairement être scindées. Cela dépendra
le l’évolution future de l’application.
10. OCP : Open/Close Principle
• Une classe doit être ouverte à l'extension, mais fermée à la
modification
• Sauf pour la correction de bug, l’idée est de ne jamais modifier un
code déjà existant surtout s’il a déjà été testé et approuvé
• Faire bon usage de l’abstraction et du polymorphisme afin d’étendre
un comportement sans le modifier (Decorator, Factory, Observer).
• La composition avec le pattern Strategy répond aussi à ce principe
11. OCP : Open/Close Principle
Il est probable que vous passiez plus de temps à ajouter de nouvelles
fonctionnalités que d’écrire du code neuf. Ce principe s’applique à
structurer notre code afin de nous procurer l'un des plus grands
avantages de la programmation orientée objet : la réutilisation et la
maintenabilité.
OCP
13. LSP : Liskov Substitution Principle
• Les sous-types doivent être interchangeables par leurs types de base
• Les classes enfants ne doivent jamais briser les définitions de type de
classe parente
14. LSP : Liskov Substitution Principle
Ne pas penser « tous les oiseaux volent sauf l’autruche » mais plutôt
« tous les oiseaux ne volent pas, l’autruche en est un »
LSP
15. LSP : Liskov Substitution Principle
Je dois pouvoir considérer un cercle, un rectangle ou un carré comme
n’importe quelle forme.
LSP
17. ISP : Interface Segregation Principle
• Un client ne doit pas être forcé de dépendre de méthodes qu’il
n’utilise pas
• Préférer plusieurs interfaces spécifiques pour chaque client plutôt
qu'une seule interface générale : interfaces de tête vs interfaces de
rôle
• Créer des interfaces à grains fin qui sont spécifiques au client
18. ISP : Interface Segregation Principle
Un client ne doit pas être forcé de dépendre de méthodes qu’il n’utilise
pas
LSP
20. ISP : Interface Segregation Principle
• Il faut dépendre des abstractions, pas des implémentations
• L'idée est que chaque point de contact entre deux modules soit
matérialisé par une abstraction
• Une abstraction se matérialise par une interface ou une classe de
base qui est aussi l’abstraction de classe plus élevé
• Les interfaces documentent
21. ISP : Interface Segregation Principle
Les modules de haut niveau ne doivent pas dépendre de modules de
plus bas niveau
ISP
22. Conclusion
• SOLID vs YAGNI (YouAren't Gonna Need It) : pourquoi mettre en
place tout un système de tolérance au changement dans un système
statique, avec peu de dépendances externes ?
• Il est possible de ne pas appliquer tous les principes SOLID d’un coup,
il n’est pas choquant d’ajuster les choix de conception au moment où
l’on en a besoin (refactoring)
• La raison, le pragmatisme et l’expérience vont nous permettre
d’arbitrer. Avec l’expérience vous pourrez appliquer
systématiquement SOLID avec le même effort, mais probablement
pas dès le début
Notes de l'éditeur
https://amethyste16.wordpress.com/2016/02/02/ecrire-du-code-solid/
PRINCIPE, pas pattern. Si SOLID va nous dire ce qu’il faudrait faire, les patterns vont nous dire comment le faire.
Cela n’a pas de sens d’entamer un chantier du style:
Mardi on fait S
Lundi O
…
https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
PRINCIPE, pas pattern. Si SOLID va nous dire ce qu’il faudrait faire, les patterns vont nous dire comment le faire.
Au niveau du vocabulaire une entité peut désigner une fonction, un module, mais dans notre contexte ce sera plutôt une classe.
Il y a le mauvais développeur et le bon développeur, le mauvais développeur il voit un clavier il code. Le bon développeur il voit un clavier il code… SOLID.
https://fr.wikipedia.org/wiki/Principe_de_responsabilit%C3%A9_unique
https://fr.wikibooks.org/wiki/Patrons_de_conception/Cha%C3%AEne_de_responsabilit%C3%A9
Un bug n’est pas une raison de changer.
Facile à comprendre dur à appréhender, à bien découper : dépend beaucoup du futur de l’application.
https://fr.wikipedia.org/wiki/Principe_de_responsabilit%C3%A9_unique
https://fr.wikibooks.org/wiki/Patrons_de_conception/Cha%C3%AEne_de_responsabilit%C3%A9
L’idée est que si une responsabilité évolue, alors on ne risque pas de casser les autres pour avoir introduit des couplages forts comme du code imbriqué l’un dans l’autre.
http://sogilis.com/blog/srp-single-responsibility-principle-code/
Il nous explique que les classes qui implémentent cette interface ont alors 2 responsabilités (la gestion de la connexion et la communication), mais qu’elles ne doivent pas nécessairement être scindées : tout dépend de la manière dont l’application évolue !Si les évolutions ne porterons que sur la gestion de la connexion, alors oui, pour minimiser la rigidité, éviter de toucher à la partie communication lorsqu’on modifie la gestion de la connexion, etc., il est préférable de dissocier ces 2 responsabilités.En revanche, si les futures évolutions portent sur ces 2 aspects en même temps, alors cette séparation n’est pas nécessaire. Elle est même déconseillée pour éviter de compliquer l’architecture de manière inutile.
PRINCIPE, pas pattern. Si SOLID va nous dire ce qu’il faudrait faire, les patterns vont nous dire comment le faire.
PRINCIPE, pas pattern. Si SOLID va nous dire ce qu’il faudrait faire, les patterns vont nous dire comment le faire.
http://www.jasondeoliveira.com/2010/11/tutorial-solid-quality-code-in-c-part3.html
Historiquement les interfaces ont été développées pour introduire des couplages faibles. Ce n’est donc pas la classe concrète qui a besoin d’une interface, mais le client. On a donc aucune raison de proposer à un client des méthodes dont il n’a pas besoin.
Ce type d’interface qui cible le besoin est appelée interface de rôle. Elles sont par définition plus restreintes que les interfaces de tête et surtout moins sensibles au problème LSP.
Historiquement les interfaces ont été développées pour introduire des couplages faibles. Ce n’est donc pas la classe concrète qui a besoin d’une interface, mais le client. On a donc aucune raison de proposer à un client des méthodes dont il n’a pas besoin.
Ce type d’interface qui cible le besoin est appelée interface de rôle. Elles sont par définition plus restreintes que les interfaces de tête et surtout moins sensibles au problème LSP.
http://www.dotnetdojo.com/concevoir-des-applications-solid-avec-isp/
Lorsqu’on y réfléchi, le fait d’avoir une interface « trop grosse » va vite entraîner des problèmes d’efficacité : chaque classe implémentant l’interface devra implémenter toutes les méthodes de l’interface. Il est donc intéressant de réduire cette interface au minimum nécessaire.
En règle générale les modules de haut niveau contiennent le cœur – business – des applications. Lorsque ces modules dépendent de modules de plus bas niveau, les modifications effectuées dans les modules « bas niveau » peuvent avoir des répercussions sur les modules « haut niveau » et les « forcer » à appliquer des changements. Une solution consiste à rendre indépendants les modules de haut et bas niveau
Permet aussi la documentation
Notre logiciel sera effectivement extrêmement robuste envers des événements qui n’auront pas lieu, ou avec un impact minime. L’investissement effectué s’avère peu productif, avec un retour sur investissement négatif.
La raison, le pragmatisme et l’expérience vont nous permettre d’arbitrer sur une conception plus ou moins abstraite, plus ou moins tolérante au changement