Les principes SOLID font partie des bases de la programmation orientée objet. Cependant, qui n'est jamais intervenu sur un projet avec l'ensemble du code fortement couplé ? Avec de ce fait de grandes difficultés à le tester unitairement ? L'objectif de cette présentation est de démontrer sur un cas d'usage comment l'utilisation d'interfaces et l'injection de dépendances va nous permettre d'améliorer ce code et de le rendre testable.
[Scrum Day 2011] Outillage Agile dans un environnement Microsoft
[Agile Tour Paris 2014] Comment rendre testable du code qui ne l'est pas ?
1. Comment rendre testable du code qui ne l’est pas ?
Christophe HERAL
@ChrisHeral
Neotech Solutions - Bordeaux
2. Qui suis-je ?
• Consultant .NET à Bordeaux
• Agiliste
Et surtout :
• Artisan logiciel
3. Une attention continue à l'excellence
technique et à une bonne conception
renforce l’Agilité.
Les meilleures architectures,
spécifications et conceptions
émergent d'équipes auto-organisées.
4. Code existant
Méconnaissance des méthodes d’ingénierie
Fortement couplé / trop de responsabilités
Sans tests -> Difficilement testable
Architecture classique en couches
5. Les choses à ne pas faire : STUPID
Singleton
Tight Coupling
Untestable
Premature Optimization
Indescriptive Naming
Duplication
6. Clean Code
Définition :
1. Passe tous les tests
2. N’est pas redondant
3. Exprime clairement les intentions du programmeur
4. Minimise le nombre d’entités (classes et méthodes)
“Writing code that a computer can understand is
science, but writing code another programmer can
understand is an art” - Jason Gorman
7. Clean Code – Comment y parvenir
TDD
Principes SOLID
KISS / YAGNI / DRY
Règle du boy-scout : « Toujours laisser le code plus
propre que vous ne l’avez trouvé en arrivant. »
8. SOLID : 5 principes de base
Principes d’architecture logicielle en programmation orientée objet
Objectif : permettre un développement plus fiable et plus robuste
S Responsabilité unique
(Single responsibility principle)
O Ouvert/fermé
(Open/closed principle)
L Substitution de Liskov
(Liskov Substitution Principle)
I Ségrégation des interfaces
(Interface Segregation Principle)
D Inversion des dépendances
(Dependency Inversion Principle)
9. SRP - Single Responsability Principle
(Responsabilité unique)
« Si une classe a plus d'une responsabilité, alors
ces responsabilités deviennent couplées. (…) »
- Robert C. Martin
12. OCP – Open/Closed Principle
(Ouvert/fermé)
« Les modules qui se conforment au principe ouvert/fermé
ont deux attributs principaux :
1 - Ils sont "Ouverts pour l'extension". (...)
2 - Ils sont "Fermés à la modification". (…) »
- Robert C. Martin
15. LSP – Liskov Substitution Principle
(Substitution de Liskov)
« Les sous-types doivent être remplaçables
par leur type de base. » - Robert C. Martin
18. ISP – Interface Segregation Principle
(Séparation des interfaces)
Les clients d'une entité logicielle ne doivent
pas avoir à dépendre d'une interface qu'ils
n'utilisent pas.
21. DIP – Dependency Inversion Principle
(Inversion des dépendances)
Principe d’Hollywood :
« Ne nous appelez pas, nous vous appellerons. »
Dépendance
A B
A I
Dépendance Implémente
B
25. Soyez indépendants !
Ne pas dépendre d’un service / une API externe
Ne pas dépendre d’une base de données
Ne pas dépendre de données de production
Ne pas dépendre du jour et de l’heure
26. Simuler des dépendances
Isolation = Fondamental
Rend le test véritablement unitaire
SUT
Dépendance
Doublure
Interface
On simule
=
l’implémentation attendue
Automatisation avec un framework de mocking (ex : Moq)
28. DRY – Don’t Repeat Yourself
« Dans un système, toute connaissance doit avoir une
représentation unique, non-ambiguë, faisant autorité. »
- Andy Hunt et Dave Thomas (The Pragmatic Programmer)
29. Composition over inheritance
• « Is a » VS « Has a »
• Meilleure testabilité
• Casse l’encapsulation
• Nécessaire pour l’application de certains patterns
30. Code Smells (« Odeurs du code »)
• Méthodes longues / Grosses classes
• Longue liste de paramètres
• Utilisation de switch
• GOTO / Codes de retour d’erreur
• Noms de méthodes avec ET/OU
• Code dupliqué
• Code mort
• Navigation transitive
• Nombres magiques
• Généralité spéculative
• Commentaires
• Séparation verticale
• Chirurgie avec fusil à pompe
• Héritage parallèle
31. Repérer les Code Smells
• Relecture de code
-> Pair Programming
-> « Clean Code Cheat Sheet » de Urs Enzler
• Analyse statique de code
-> Repère des erreurs de conception / programmation
-> Outils : FxCop, StyleCop, Resharper, NDepend
Présentation orientée Software Craftsmanship
Valable quelque soit la techno utilisée.
Démos effectuées dans les technos .NET (C#, NUnit, Moq, …).
Méconnaissance des méthodes d’ingénierie
Fortement couplé / trop de responsabilités
Sans tests -> Difficilement testable
Architecture classique en couches
Méthodes statiques / singletons / instanciations directes
Fort couplage entre classes / dépendances
Remplacement systématique de la duplication par de l’héritage
Classes avec trop de responsabilités
Mélange de l’IHM avec la logique métier
TDD
Utilisation d’interfaces
Principes SOLID
KISS / YAGNI / DRY
Design Patterns
Détection de Code Smells
Principes d’architecture logicielle en programmation orientée objet
Objectif : permettre un développement plus fiable et plus robuste
Diminuer le couplage
Favoriser l’encapsulation
« Si une classe a plus d'une responsabilité, alors ces responsabilités deviennent couplées.
Des modifications apportées à l'une des responsabilités peuvent porter atteinte ou inhiber la capacité de la classe de remplir les autres.
Ce genre de couplage amène à des architectures fragiles qui dysfonctionnent de façon inattendues lorsqu'elles sont modifiées. » - Robert C. Martin
« Les modules qui se conforment au principe ouvert/fermé ont deux attributs principaux :
1 - Ils sont "Ouverts pour l'extension". Cela signifie que le comportement du module peut être étendu, que l'on peut faire se comporter ce module de façons nouvelles et différentes si les exigences de l'application sont modifiées, ou pour remplir les besoins d'une autre application.
2 - Ils sont "Fermés à la modification". Le code source d'un tel module ne peut pas être modifié. Personne n'est autorisé à y apporter des modifications. » - Robert C. Martin
Préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une seule interface générale.
Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau.
Les deux doivent dépendre d'abstractions.
Les abstractions ne doivent pas dépendre des détails.
Les détails doivent dépendre des abstractions.
Représentation de l’inversion de contrôle
Injection par constructeur.
Configuration par code.
Librairie légère, facile d’utilisation et rapide.
Ex : SimpleInjector
Injection par constructeur.
Configuration par code.
Librairie légère, facile d’utilisation et rapide.
Ex : SimpleInjector
Les modifications de code n’ont pas à être à impacter à différents endroits.
Essence même de l’utilisation des fonctions et des méthodes.
Sous-jacent au principe de substitution de Liskov
Meilleure testabilité : Mock possible sur la dépendance, pas sur les méthodes dont on dérive
Casse l’encapsulation: Le comportement des classes dérivées peut être cassé par une modification de la classe de base
Nécessaire pour l’application de certains patterns (Strategy, Decorator)
Pas d’héritage multiple
« Is a » VS « Has a »
Différents types
Analyse des binaires
Analyse du code source