13 juillet 2013© Invenietis 2012-2013
Injection de Dépendances
…les bases
13 juillet 2013© Invenietis 2012-2013
Les Concepts
 Un de 5 principes SOLID
 Dépendances
 IoC – Inversion of Control
 ...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous allez subir…
 Programmation SOLID
 Qu’est-ce qu’une dépendanc...
13 juillet 2013© Invenietis 2012-2013
La conception SOLID
 SRP – Single responsibility principle
• Un objet ⇒ Une respons...
13 juillet 2013© Invenietis 2012-2013
Principe fondamental
- Bénéfices
- Conception clarifiée
- Evolution facilitée
- Réut...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous subissez…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?...
13 juillet 2013© Invenietis 2012-2013
Qu’est-ce qu’une dépendance ?
 Tout composant, module ou objet « D » qui est extéri...
13 juillet 2013© Invenietis 2012-2013
Le Grand Bazar des Dépendances
8
13 juillet 2013© Invenietis 2012-2013
Le Grand Bazar des Dépendances
• J’utilise « new D() » quand j’en ai besoin.
• Je n’...
13 juillet 2013© Invenietis 2012-2013
Le Grand Bazar des Dépendances
• J’utilise « new D() » quand j’en ai besoin.
• Je n’...
13 juillet 2013© Invenietis 2012-2013
Le Grand Bazar des Dépendances
• J’utilise « new D() » quand j’en ai besoin.
• Je n’...
13 juillet 2013© Invenietis 2012-2013
Le Grand Bazar des Dépendances
• J’utilise « new D() » quand j’en ai besoin.
• Je n’...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous subissez…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?...
13 juillet 2013© Invenietis 2012-2013
Je n’utilise pas « new » : Inversion of Control
 Je ne contrôle plus la création de...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
Concrètement, simplement.
• « new »
• Pas « new »
• Champ pour D
• Propriété
• Métho...
13 juillet 2013© Invenietis 2012-2013
New is NOT dead! (Faut-il tout “externaliser” ?)
 Une Entité est “stateful”
 Elle ...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous subissez…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?...
13 juillet 2013© Invenietis 2012-2013
Le Grand Extérieur ou « How to not new? »
 Ambiant Context
 Et son méchant associé...
13 juillet 2013© Invenietis 2012-2013
Les (très) mauvais Singletons
 Très mauvais
 Acceptable… Mais uniquement car accep...
13 juillet 2013© Invenietis 2012-2013
Le bon Singleton : Ambiant Context
 Un Ambiant Context est une Abstraction
 Qui ne...
13 juillet 2013© Invenietis 2012-2013
The good old Service Provider
 Since .Net framework 1.0
 Au cœur du Component Mode...
13 juillet 2013© Invenietis 2012-2013
Le Service Locator : une aberration
 « Un Anneau pour les gouverner tous. »
 Tenta...
13 juillet 2013© Invenietis 2012-2013
Le Grand Extérieur : L’Usine Center
 Exemple de Factory Methods (2 méthodes statiqu...
13 juillet 2013© Invenietis 2012-2013
Le Grand Extérieur : L’Usine Center
 Mais?! DFactory est donc un singleton!
 Si so...
13 juillet 2013© Invenietis 2012-2013
Pour le Grand Extérieur, donc…
 Ambiant Context
 Et son méchant associé le Singlet...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous subissez…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?...
13 juillet 2013© Invenietis 2012-2013
L’Injection des Dépendances (Dependency Injection)
• J’utilise « new D() » quand j’e...
13 juillet 2013© Invenietis 2012-2013
« Don’t call us, we’ll call you. »
 Notion de « Graphe de Dépendances »
 Ces dépen...
13 juillet 2013© Invenietis 2012-2013
« Don’t call us, we’ll call you. »
 Notion de « Graphe de Dépendances »
 Ces dépen...
13 juillet 2013© Invenietis 2012-2013
« Don’t call us, we’ll call you. »
 Notion de « Graphe de Dépendances »
 Ces dépen...
13 juillet 2013© Invenietis 2012-2013
static C GiveMeC()
{
var g = new G( "db1" );
var f = new F( "db2" );
return new C( n...
13 juillet 2013© Invenietis 2012-2013
Programming to Abstractions
 Qui décide des implémentations ?
class C : IC
{
public...
13 juillet 2013© Invenietis 2012-2013
Programming to Abstractions
 Qui décide des implémentations ?
class C : IC
{
public...
13 juillet 2013© Invenietis 2012-2013
static IC GiveMeC()
{
var g = new G( "db1" );
var f = new FGoogle( 42 );
return new ...
13 juillet 2013© Invenietis 2012-2013
Résoudre les Dépendances
 Abstraction  Concretion
 Gestion des instances : le Cyc...
13 juillet 2013© Invenietis 2012-2013
 EV3 n’est plus Transient: il est lié à la requête en cours.
 En remplaçant HttpCo...
13 juillet 2013© Invenietis 2012-2013
Le discours que vous subissez…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?...
13 juillet 2013© Invenietis 2012-2013
La règle d’or de la Gestion des Ressources
 Ou encore : celui qui obtient un Objet ...
13 juillet 2013© Invenietis 2012-2013
Les « Scopes » de Vie
 Une règle simple à respecter (exemple en environnement Web)
...
13 juillet 2013© Invenietis 2012-2013
Cycle de Vie et réutilisabilité
 A tout Objet concret est associé un Cycle de Vie, ...
13 juillet 2013© Invenietis 2012-2013
Cycle de Vie et réutilisabilité
 A tout Objet concret est associé un Cycle de Vie, ...
13 juillet 2013© Invenietis 2012-2013
Allez, c’est bientôt fini…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?
 Q...
13 juillet 2013© Invenietis 2012-2013
Les responsabilités d’un Container de DI
 Associer une Abstraction à une
classe Con...
13 juillet 2013© Invenietis 2012-2013
La DI et le .Net framework
 Une histoire courte… surtout du point de vue de Microso...
13 juillet 2013© Invenietis 2012-2013
En pratique, 2 exemples
 Castle Windsor
 Très complet, mature et très bien conçu
...
13 juillet 2013© Invenietis 2012-2013
 On créé un Container
 On le configure (Register)
 On l’utilise (Resolve)
 On si...
13 juillet 2013© Invenietis 2012-2013
Principe de fonctionnement
 On créé un Container
 On le configure (Register)
 En ...
13 juillet 2013© Invenietis 2012-2013
A quoi cela ressemble ?
 Simple…
55
interface IA
{
void DoSomething();
}
class A : ...
13 juillet 2013© Invenietis 2012-2013
Tout ça pour ça ?
 Une énorme Factory éminemment configurable ?
• La configuration ...
13 juillet 2013© Invenietis 2012-2013
Allez, c’est bientôt fini…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?
 Q...
13 juillet 2013© Invenietis 2012-2013
Bien utiliser la DI != Savoir utiliser un Container
 Trop souvent sur- ou mal- util...
13 juillet 2013© Invenietis 2012-2013
Bien utiliser la DI != Savoir utiliser un Container
 Trop souvent sur- ou mal- util...
13 juillet 2013© Invenietis 2012-2013
SEAM et COMPOSITION ROOT (Démo)
 Un framework (très) simple
 Qui peut fonctionner ...
13 juillet 2013© Invenietis 2012-2013
 Chercher le SEAM…
 …y introduire l’unique appel au Container de DI
 …pour obteni...
13 juillet 2013© Invenietis 2012-2013
Dernière ligne droite…
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?
 Qu’es...
13 juillet 2013© Invenietis 2012-2013
Lorsque la résolution doit être différée…
 Parce que la dépendance a solliciter dép...
13 juillet 2013© Invenietis 2012-2013
Une Solution, plusieurs mises en œuvre
 Introduire une indirection sous la forme d’...
13 juillet 2013© Invenietis 2012-2013
Un problème… de dépendances !
 La Factory est liée au type du Container utilisé dan...
13 juillet 2013© Invenietis 2012-2013
Enfin !
 Programmation SOLID
 Qu’est-ce qu’une dépendance ?
 Qu’est-ce que l’Inve...
13 juillet 2013© Invenietis 2012-2013
Quelques pièges de la DI
 Les Containers ne sont pas identiques… loin s’en faut
 M...
13 juillet 2013© Invenietis 2012-2013
Extensibilité des Containers
 Unity, Castle, AutoFac, etc… sont réellement extensib...
13 juillet 2013© Invenietis 2012-2013
Conclusion
 Concevoir indépendamment d’un Container
 Comprendre les enjeux de la C...
13 juillet 2013© Invenietis 2012-2013
Bibliographie
 “Dependency Injection in .Net’, Mark Seeman, Manning 2012
 http://w...
13 juillet 2013© Invenietis 2012-2013
Cycle de Vie: les deux approches
 Le Container traque les instances (et leurs dépen...
Prochain SlideShare
Chargement dans…5
×

Injection de dependances - Les bases

1 342 vues

Publié le

Les bases de l'injection de dépendances (Dependency Injection) sont présentées en partant de la notion même de dépendances. Les quelques fragments de code sont en C#, mais les aspects traités sont indépendants du .Net framework.

Publié dans : Technologie
0 commentaire
1 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
1 342
Sur SlideShare
0
Issues des intégrations
0
Intégrations
5
Actions
Partages
0
Téléchargements
30
Commentaires
0
J’aime
1
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Injection de dependances - Les bases

  1. 1. 13 juillet 2013© Invenietis 2012-2013 Injection de Dépendances …les bases
  2. 2. 13 juillet 2013© Invenietis 2012-2013 Les Concepts  Un de 5 principes SOLID  Dépendances  IoC – Inversion of Control  Objets  « Stateful » ou « Stateless »  Cycle de vie  Seam & Composition Root 2
  3. 3. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous allez subir…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 3
  4. 4. 13 juillet 2013© Invenietis 2012-2013 La conception SOLID  SRP – Single responsibility principle • Un objet ⇒ Une responsabilité  OCP – Open/Closed principle • Un composant doit être extensible, pas modifiable.  LSP – Liskov substitution principle • N’importe quel type compatible doit être substituable.  ISP – Interface segregation principle • Des interfaces spécialisées plutôt qu’une générale.  DIP – Dependency injection principle • Hollywood principle: « Don’t call us, we’ll call you » 4
  5. 5. 13 juillet 2013© Invenietis 2012-2013 Principe fondamental - Bénéfices - Conception clarifiée - Evolution facilitée - Réutilisabilité élevée - Mise en œuvre - Définir des interfaces (ou des classes abstraites) et les utiliser - Eviter le « new » Depend on Abstractions, not Concretions 5
  6. 6. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous subissez…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  La résolution de dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 6
  7. 7. 13 juillet 2013© Invenietis 2012-2013 Qu’est-ce qu’une dépendance ?  Tout composant, module ou objet « D » qui est extérieur au composant, module ou objet « C » et dont « C » a besoin pour fonctionner.  C’est bien ou c’est mal ?  Ça dépend…  …et des fois, ça dépasse. 7 Objet C (un Contrôleur par exemple) ConcludeSubscription() { Cette méthode doit envoyer un mail… } Objet D (un Service d’envoi de Mail par exemple) SendMail( recipient, body ) { Cette méthode sait envoyer un mail… } Dépendance
  8. 8. 13 juillet 2013© Invenietis 2012-2013 Le Grand Bazar des Dépendances 8
  9. 9. 13 juillet 2013© Invenietis 2012-2013 Le Grand Bazar des Dépendances • J’utilise « new D() » quand j’en ai besoin. • Je n’utilise pas « new ». 9
  10. 10. 13 juillet 2013© Invenietis 2012-2013 Le Grand Bazar des Dépendances • J’utilise « new D() » quand j’en ai besoin. • Je n’utilise pas « new ». • J’ai un champ qui contient le D à utiliser. • Je n’ai pas de champ pour D. 10
  11. 11. 13 juillet 2013© Invenietis 2012-2013 Le Grand Bazar des Dépendances • J’utilise « new D() » quand j’en ai besoin. • Je n’utilise pas « new ». • J’ai un champ qui contient le D à utiliser. • Ce champ est exposé en tant que Propriété. • Ce champ est configuré via une méthode. • Ce champ ne peut être configuré que depuis le constructeur. • Je n’ai pas de champ pour D. 11
  12. 12. 13 juillet 2013© Invenietis 2012-2013 Le Grand Bazar des Dépendances • J’utilise « new D() » quand j’en ai besoin. • Je n’utilise pas « new ». • J’ai un champ qui contient le D à utiliser. • Ce champ est exposé en tant que Propriété. • Ce champ est configuré via une méthode. • Ce champ ne peut être configuré que depuis le constructeur. • Je n’ai pas de champ pour D. • Il m’est passé en paramètre de méthode. • Je vais chercher D dans le « Grand Extérieur » quand j’en ai besoin. 12
  13. 13. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous subissez…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 13
  14. 14. 13 juillet 2013© Invenietis 2012-2013 Je n’utilise pas « new » : Inversion of Control  Je ne contrôle plus la création de la ressource.  Je me contente d’utiliser un objet (idéalement une Abstraction)  Je ne contrôle plus son Cycle de Vie J’ai abandonné le contrôle… Je viens de vivre une inversion de contrôle. Ce n’est ni la première, ni la dernière. A chaque IoC, les développeurs souffrent. 14
  15. 15. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { public void Method() { D dep = ??? dep.Run(); } } 15
  16. 16. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { public void Method() { D dep = new D(); dep.Run(); } } 16
  17. 17. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { D _dep; public void Method() { _dep.Run(); } } 17 ???
  18. 18. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { D _dep; public D Dep { get { return _dep; } set { _dep = value; } } public void Method() { _dep.Run(); } } 18
  19. 19. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { D _dep; public void Init( D dep, int rate ) { _dep = dep; ... } public void Method() { _dep.Run(); } } 19
  20. 20. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { readonly D _dep; public C( D dep, int rate ) { _dep = dep; ... } public void Method() { _dep.Run(); } } 20
  21. 21. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { public void Method( D dep ) { dep.Run(); } } 21
  22. 22. 13 juillet 2013© Invenietis 2012-2013 Concrètement, simplement. • « new » • Pas « new » • Champ pour D • Propriété • Méthode • Constructeur • Pas de champ pour D • Paramètre de méthode • Le « Grand Extérieur » public class C { public void Method() { D dep = ??? dep.Run(); } } 22
  23. 23. 13 juillet 2013© Invenietis 2012-2013 New is NOT dead! (Faut-il tout “externaliser” ?)  Une Entité est “stateful”  Elle porte de la donnée (qui, souvent, la définit).  Une entité est (souvent) créée lorsque l’on en a besoin via “new”  Un Service est “stateless”  Plusieurs objest (instances) de MailService représentent, de fait, le même service  Les Services sont (très souvent) “injectables”  Les Services dependent des Entités  En théorie, le contraire est faux 23 Ce que j’aime dans le développement, c’est que, parfois, c’est plus subtil que cela, et que ces règles doivent s’accomoder d’exceptions.
  24. 24. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous subissez…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 24
  25. 25. 13 juillet 2013© Invenietis 2012-2013 Le Grand Extérieur ou « How to not new? »  Ambiant Context  Et son méchant associé le Singleton  Service Provider  Et son collègue le Service Locator  Factory Method  Et son grand frère l’Abstract Factory Method 25 Si l’on injecte pas, il faut aller chercher D “dans le Grand Extérieur”.
  26. 26. 13 juillet 2013© Invenietis 2012-2013 Les (très) mauvais Singletons  Très mauvais  Acceptable… Mais uniquement car accepté (opinion personnelle)… SuperConfig cfg = (SuperConfig)ConfigurationManager.GetSection( "SuperApp" ); public static class Connection { static SqlConnection _con; static public SqlConnection Default { get { return _con ?? (_con = new SqlConnection( "…" ) ); } } } static ILogger _log = LogManager.GetLogger<Connection>(); 26
  27. 27. 13 juillet 2013© Invenietis 2012-2013 Le bon Singleton : Ambiant Context  Un Ambiant Context est une Abstraction  Qui ne fait que fournir de la donnée (lecture seule) ou agir sur une information « totalement globale ».  Cette donnée (très globale) étant susceptible d’intéresser n’importe quel sous-système, n’importe quand.  Un Ambiant Context par excellence  Le TimeProvider À consommer sans modération en lieu et place de DateTime.UtcNow. 27
  28. 28. 13 juillet 2013© Invenietis 2012-2013 The good old Service Provider  Since .Net framework 1.0  Au cœur du Component Model, mais aussi de XAML.  Simple, efficace et souple  si le Service demandé n’existe pas, null est retourné. namespace System { public interface IServiceProvider { object GetService( Type serviceType ); } } 28
  29. 29. 13 juillet 2013© Invenietis 2012-2013 Le Service Locator : une aberration  « Un Anneau pour les gouverner tous. »  Tentative d’Abstraction de l’IoC, qui réussit le tour de force d’être à la fois « sur et sous-designé »…  ne respecte même pas le contrat du Service Provider (qu’il spécialise).  A oublier! namespace Microsoft.Practices.ServiceLocation { public interface IServiceLocator : IServiceProvider { object GetInstance( Type serviceType ); object GetInstance( Type serviceType, string key ); IEnumerable<object> GetAllInstances( Type serviceType ); TService GetInstance<TService>(); TService GetInstance<TService>( string key ); IEnumerable<TService> GetAllInstances<TService>(); } } 29
  30. 30. 13 juillet 2013© Invenietis 2012-2013 Le Grand Extérieur : L’Usine Center  Exemple de Factory Methods (2 méthodes statiques, 2 méthodes d’instances)  En pratique, on appelle une méthode statique: string fileName = @"C:TempGoogleHomeDownloaded.htm"; WebRequest req = WebRequest.Create( "http://www.google.com" ); using( WebResponse resp = req.GetResponse() ) using( Stream stream = resp.GetResponseStream() ) using( Stream file = File.Create( fileName ) ) { stream.CopyTo( file ); } 30 public class C { public void Method() { D dep = DFactory.CreateOneD(); dep.Run(); } }
  31. 31. 13 juillet 2013© Invenietis 2012-2013 Le Grand Extérieur : L’Usine Center  Mais?! DFactory est donc un singleton!  Si son fonctionnement doit pouvoir être paramétré, on introduit une Abstract Factory.  Abstract Factory public class C { public void Method() { D dep = theFactory.CreateOneD(); dep.Run(); } } public class C { public void Method() { D dep = DFactory.CreateOneD(); dep.Run(); } } Mais ?! theFactory… est une dépendance à résoudre ! 31
  32. 32. 13 juillet 2013© Invenietis 2012-2013 Pour le Grand Extérieur, donc…  Ambiant Context  Et son méchant associé le Singleton  Service Provider  Et son collègue le Service Locator  Factory Method  Et son grand frère l’Abstract Factory Method Les dépendances sont masquées, implicites, invisibles sauf à inspecter l’implémentation. 32
  33. 33. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous subissez…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 33
  34. 34. 13 juillet 2013© Invenietis 2012-2013 L’Injection des Dépendances (Dependency Injection) • J’utilise « new D() » quand j’en ai besoin. • Je n’utilise pas « new ». • J’ai un champ qui contient le D à utiliser. • Ce champ est exposé en tant que Propriété. • Ce champ est configuré via une méthode. • Ce champ ne peut être configuré que depuis le constructeur. • Je n’ai pas de champ pour D. • Il m’est passé en paramètre de méthode. • Je vais chercher D dans le « Grand Extérieur » quand j’en ai besoin. Parameter Injection Contructor Injection Method Injection Property Injection 34
  35. 35. 13 juillet 2013© Invenietis 2012-2013 « Don’t call us, we’ll call you. »  Notion de « Graphe de Dépendances »  Ces dépendances sont fournies class C { public C( D dep ) { ... } } 35
  36. 36. 13 juillet 2013© Invenietis 2012-2013 « Don’t call us, we’ll call you. »  Notion de « Graphe de Dépendances »  Ces dépendances sont fournies class C { public C( D dep ) { ... } } class D { public D( E e, G db2 ) { ... } } 36
  37. 37. 13 juillet 2013© Invenietis 2012-2013 « Don’t call us, we’ll call you. »  Notion de « Graphe de Dépendances »  Ces dépendances sont fournies class C { public C( D dep ) { ... } } class D { public D( E e, G db2 ) { ... } } class G { public G( string dbName ) { ... } } class F { public F( string dbName ) { ... } } class E { public E( F db, G db2 ) { ... } } 37
  38. 38. 13 juillet 2013© Invenietis 2012-2013 static C GiveMeC() { var g = new G( "db1" ); var f = new F( "db2" ); return new C( new D( new E( f, g ), g ) ); } « Don’t call us, we’ll call you. »  Notion de « Graphe de Dépendances »  Ces dépendances sont fournies class C { public C( D dep ) { ... } } class D { public D( E e, G db2 ) { ... } } class G { public G( string dbName ) { ... } } class F { public F( string dbName ) { ... } } class E { public E( F db, G db2 ) { ... } } 38
  39. 39. 13 juillet 2013© Invenietis 2012-2013 Programming to Abstractions  Qui décide des implémentations ? class C : IC { public C( ID dep ) { ... } } 39 ?
  40. 40. 13 juillet 2013© Invenietis 2012-2013 Programming to Abstractions  Qui décide des implémentations ? class C : IC { public C( ID dep ) { ... } } class D2 : ID { public D( IE e, IG db2 ) { ... } } class G : IG { public G( string d ) { ... } } class FGoogle : IF { public FGoogle( int ratio ) { ... } } class EV3 : IE { public EV3( IF db, IG db2 ) { ... } } 40
  41. 41. 13 juillet 2013© Invenietis 2012-2013 static IC GiveMeC() { var g = new G( "db1" ); var f = new FGoogle( 42 ); return new C( new D2( new EV3( f, g ), g ) ); } Programming to Abstractions  Qui décide des implémentations ? class C : IC { public C( ID dep ) { ... } } class D2 : ID { public D( IE e, IG db2 ) { ... } } class G : IG { public G( string d ) { ... } } class FGoogle : IF { public FGoogle( int ratio ) { ... } } class EV3 : IE { public EV3( IF db, IG db2 ) { ... } } 41
  42. 42. 13 juillet 2013© Invenietis 2012-2013 Résoudre les Dépendances  Abstraction  Concretion  Gestion des instances : le Cycle de Vie  FGoogle et G sont des « Singletons », C, D et EV3 sont « Transients »  Singleton: toujours la même instance retournée à chaque fois que l’on en a besoin.  Transient: toujours un nouvel objet à chaque fois que l’on en a besoin. static FGoogle _f; static G _g; static IC GiveMeC() { if( _f == null ) _f = new FGoogle( 42 ); if( _g == null ) _g = new G( "db1" ); return new C( new D( new EV3( _f, _g ), _g ) ); } 42
  43. 43. 13 juillet 2013© Invenietis 2012-2013  EV3 n’est plus Transient: il est lié à la requête en cours.  En remplaçant HttpContext.Current.Items par HttpContext.Current.Session, EV3 sera associé à la Session de l’utilisateur. static FGoogle _f; static G _g; static IC GiveMeC() { if( _f == null ) _f = new FGoogle( 42 ); if( _g == null ) _g = new G( "db1" ); IE e = (IE)HttpContext.Current.Items[typeof(IE)]; if( e == null ) { e = new EV3( _f, _g ); HttpContext.Current.Items[typeof(IE)] = e; } return new C( new D( e, _g ) ); } Entre « Singleton » et « Transient » 43
  44. 44. 13 juillet 2013© Invenietis 2012-2013 Le discours que vous subissez…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 44
  45. 45. 13 juillet 2013© Invenietis 2012-2013 La règle d’or de la Gestion des Ressources  Ou encore : celui qui obtient un Objet doit prévenir lorsqu’il n’en a plus besoin.  Pas si simple en pratique (voire un peu naïf)  Comment gérer le partage d’objets ?  La nouvelle implémentation d’un objet requiert une destruction alors que ce n’était pas le cas avant ?  C’est un des points clés de la conception à surveiller de près. Celui qui crée un Objet est celui qui le détruit. 45
  46. 46. 13 juillet 2013© Invenietis 2012-2013 Les « Scopes » de Vie  Une règle simple à respecter (exemple en environnement Web)  C’est, entre autre, ce qu’un Container de DI facilite  Mais en pratique, trop souvent, les Scopes ne s’emboitent pas gentiment comme cela. Application Session Requête Méthode X 46
  47. 47. 13 juillet 2013© Invenietis 2012-2013 Cycle de Vie et réutilisabilité  A tout Objet concret est associé un Cycle de Vie, ou Style de Vie.  Aux extrêmes, les plus simples : • Transient • Singleton  Mais aussi : • Per Thread • Per Request • Per User • Per Session • Per Graph • Per Scope • … 47 static G _g; … return _g ?? (_g = new G( "db1" )); return new G( "db1" );
  48. 48. 13 juillet 2013© Invenietis 2012-2013 Cycle de Vie et réutilisabilité  A tout Objet concret est associé un Cycle de Vie, ou Style de Vie.  Aux extrêmes, les plus simples : • Transient • Singleton  Mais aussi : • Per Thread • Per Request • Per User • Per Session • Per Graph • Per Scope • … 48 IE e = (IE)HttpContext.Current.Items[typeof(IE)]; if( e == null ) { e = new EV3( _f, _g ); HttpContext.Current.Items[typeof(IE)] = e; } return e; static G _g; … return _g ?? (_g = new G( "db1" )); return new G( "db1" ); var gInGraph = new G( "db1" ); return new C( new D( new E( _f, gInGraph ), gInGraph ) );
  49. 49. 13 juillet 2013© Invenietis 2012-2013 Allez, c’est bientôt fini…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 49
  50. 50. 13 juillet 2013© Invenietis 2012-2013 Les responsabilités d’un Container de DI  Associer une Abstraction à une classe Concrète  Obtenir un Objet  Résoudre ses dépendances  Gérer le Cycle de Vie des Objets Abstraction ConcretionInstanciation Dependencies 50 …Et que ce soit facile à configurer et à utiliser. …Et si possible, que cela offre d’autres capacités, notamment permettre des approches « Aspect Oriented Programming »
  51. 51. 13 juillet 2013© Invenietis 2012-2013 La DI et le .Net framework  Une histoire courte… surtout du point de vue de Microsoft  Spring 1.0 est publié officiellement en mars 2004. 51 From Dependency injection in .Net, Manning 2012
  52. 52. 13 juillet 2013© Invenietis 2012-2013 En pratique, 2 exemples  Castle Windsor  Très complet, mature et très bien conçu  Apache License 2.0  Un des seuls à offrir le tracking d’instances (avec AutoFac)  Unity  Issu du groupe Microsoft’s patterns & practices (p&p), supporté par Microsoft  Microsoft Public License (Ms-PL)  Complet, correctement extensible 52
  53. 53. 13 juillet 2013© Invenietis 2012-2013  On créé un Container  On le configure (Register)  On l’utilise (Resolve)  On signale la fin de l’utilisation d’un objet (Release) Principe de fonctionnement 53 Register Resolve Release
  54. 54. 13 juillet 2013© Invenietis 2012-2013 Principe de fonctionnement  On créé un Container  On le configure (Register)  En enregistrant  Des Types concrets  Des associations entre Abstractions (interfaces) et des Types concrets  En précisant  Le Style de Vie  Des configurations de créations  On l’utilise (Resolve)  En résolvant  Des Abstractions  Avec si besoin des paramètres  On signale la fin de l’utilisation d’un objet (Release)  Pour certains Containers et/ou Styles de Vie 54 Register Resolve Release
  55. 55. 13 juillet 2013© Invenietis 2012-2013 A quoi cela ressemble ?  Simple… 55 interface IA { void DoSomething(); } class A : IA { public void DoSomething() { Console.WriteLine( "A n°{0} do something.", GetHashCode() ); } } [TestFixture] public class RegisterResolve { [Test] public void RegisterAndResolve() { UnityContainer c = new UnityContainer(); // Register c.RegisterType<IA, A>( new ContainerControlledLifetimeManager() ); // Resolve var a = c.Resolve<IA>(); a.DoSomething(); } }
  56. 56. 13 juillet 2013© Invenietis 2012-2013 Tout ça pour ça ?  Une énorme Factory éminemment configurable ? • La configuration est centralisée • Elle peut s’exprimer en code et/ou en ressources (typiquement en Xml) • Les dépendances sont gérées automatiquement, quelque soit leurs niveaux  Un super ServiceProvider ? • Les implémentations sont masquées, il devient facile de travailler avec des Abstractions • Le cycle de vie des objets est géré par le Container, je ne m’en occupe plus 56 Oui ! Mais…
  57. 57. 13 juillet 2013© Invenietis 2012-2013 Allez, c’est bientôt fini…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 57
  58. 58. 13 juillet 2013© Invenietis 2012-2013 Bien utiliser la DI != Savoir utiliser un Container  Trop souvent sur- ou mal- utilisé  Dependency Injection != Utiliser un Container 58 Outillage Conception Pas de Container de DI Container de DI Pas de DI Couplage fort, problématiques techniques (constructions, cycle de vie) intriquées avec le Métier. Service Locator Anti-Pattern. Dépendances invisibles, difficile à maintenir. DI Codage à la main de l’obtention/instanciation des dépendances. De nombreux bénéfices associés.
  59. 59. 13 juillet 2013© Invenietis 2012-2013 Bien utiliser la DI != Savoir utiliser un Container  Trop souvent sur- ou mal- utilisé  Un Container de DI n’est qu’un facilitateur  Une bonne architecture n’exige pas de Container  On peut toujours décider de ne pas utiliser de Container  Avant de l’utiliser, il y a deux notions clés à comprendre  SEAM : la soudure, le joint  COMPOSITION ROOT : le support principal de l’injection 59 Before practicing Zen, mountains were mountains and rivers were rivers. While practicing Zen, mountains are no longer mountains and rivers are no longer rivers. After realization, mountains are mountains and rivers are rivers again.
  60. 60. 13 juillet 2013© Invenietis 2012-2013 SEAM et COMPOSITION ROOT (Démo)  Un framework (très) simple  Qui peut fonctionner sans DI  C’est l’occasion de « voir » la DI à l’œuvre  Et aussi d’apprendre, un peu, à s’en servir 60 Tout framework bien conçu expose un ou quelques SEAM. Ces « soudures » sont des points centraux du framework qui instancient des COMPOSITION ROOT qui sont les objets en charge de la majorité des opérations. Dans le cadre de MVC, les objets Contrôleurs sont les principaux COMPOSITION ROOT, et le ControllerFactory le principal SEAM à considérer.
  61. 61. 13 juillet 2013© Invenietis 2012-2013  Chercher le SEAM…  …y introduire l’unique appel au Container de DI  …pour obtenir la racine de composition  Toutes les dépendances de la racine de composition sont résolues…  …la racine est opérationnelle  …le système fonctionne. 61 Mise en œuvre de la DI C’est souvent aussi simple que cela. Mais, malheureusement, pas toujours…
  62. 62. 13 juillet 2013© Invenietis 2012-2013 Dernière ligne droite…  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 62
  63. 63. 13 juillet 2013© Invenietis 2012-2013 Lorsque la résolution doit être différée…  Parce que la dépendance a solliciter dépend du contexte d’exécution  Multi-tenancy  Privilèges, niveaux d’accès  On ne peut donc pas l’injecter systématiquement  Parce que la dépendance est « optionnelle »  Elle ne sera sollicitée, statistiquement, que dans quelques cas  Elle est coûteuse  on ne souhaite donc pas l’injecter systématiquement 63 Et il ne peut y avoir que deux raisons à cela !
  64. 64. 13 juillet 2013© Invenietis 2012-2013 Une Solution, plusieurs mises en œuvre  Introduire une indirection sous la forme d’une Factory  La racine de composition dépend de la Factory  La Factory est sollicitée lorsque la dépendance est nécessaire  Techniquement, la Factory peut-être :  Une simple Func<T> qui rappellera le Container Cette fonction peut comporter des paramètres supplémentaires  Une interface dédiée Avec une ou plusieurs méthodes qui renvoient la dépendance… …et des méthodes qui permettent de signaler la fin de l’utilisation (Release) 64 Factory
  65. 65. 13 juillet 2013© Invenietis 2012-2013 Un problème… de dépendances !  La Factory est liée au type du Container utilisé dans l’Application  Cela couple le « Métier » à « l’Infrastructure »  C’est mal!  Découpler ?  Func<T> est supporté par la quasi-totalité des Containers  La meilleure solution est définitivement (de mon point de vue) celle de Castle.Windsor La « Typed Factory » est une interface qui est automagiquement implémentée. http://devlicio.us/blogs/krzysztof_kozmic/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx 65
  66. 66. 13 juillet 2013© Invenietis 2012-2013 Enfin !  Programmation SOLID  Qu’est-ce qu’une dépendance ?  Qu’est-ce que l’Inversion de Contrôle ?  Si on est pas à Hollywood, on est dans le « Grand Extérieur »  L’Injection des Dépendances  Les « styles de vies » ou « combien de temps me reste-t-il à vivre? »  Les containers de DI  La bonne Dependency Injection  L’enjeu de la « résolution tardive »  Pièges et Conclusion 66
  67. 67. 13 juillet 2013© Invenietis 2012-2013 Quelques pièges de la DI  Les Containers ne sont pas identiques… loin s’en faut  Même les basiques divergent  Certains exigent un enregistrement explicite…  …d’autres décident d’instancier ce qu’ils veulent (c’est le cas de Unity)  Les enregistrements multiples, les enregistrements nommés  Le choix du constructeur quand il y en a plusieurs (faut-il prendre le plus long ou le plus court ?)  Opt-in ou Opt-out pour les propriétés ?  Les dépendances circulaires  Le contrôle du cycle de vie  Voir l’annexe qui suit pour les 2 approches. 67 UnityContainer c = new UnityContainer(); var r = c.Resolve<Random>();
  68. 68. 13 juillet 2013© Invenietis 2012-2013 Extensibilité des Containers  Unity, Castle, AutoFac, etc… sont réellement extensibles  Exemple de Unity  Corriger le comportent par défaut  Autres exemples  Gérer un fallback déterministe sur les enregistrements nommés  Introduire un mapping automatique de certaines interfaces (« Ambiant Contract ») 68
  69. 69. 13 juillet 2013© Invenietis 2012-2013 Conclusion  Concevoir indépendamment d’un Container  Comprendre les enjeux de la Conception logicielle  Viser SOLID  Utiliser les Containers comme des Facilitateurs  Ne pas dépendre de leur spécificités  Rester dans les clous  Connaître son Container  Et ne pas hésiter à l’étendre si besoin est 69
  70. 70. 13 juillet 2013© Invenietis 2012-2013 Bibliographie  “Dependency Injection in .Net’, Mark Seeman, Manning 2012  http://www.martinfowler.com/articles/injection.html Un must-read…  http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html http://kozmic.pl/2010/08/19/must-windsor-track-my-components/ Les tenants du « Le Container doit gérer totalement le cycle de vie » : ce sont principalement des membres de la communauté Windsor  http://davybrion.com/blog/2010/02/avoiding-memory-leaks-with-nservicebus-and-your-own-castle-windsor- instance/ NServiceBus s’adapte à Castle… Mais la conclusion est que NSB doit, un jour, explicitement offrir un point de Release dans le cadre de son fonctionnement.  http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/  Excellent article par le créateur de Autofac qui explique la (très bonne) gestion du Lifetime dans Autofac.  http://nblumhardt.com/2010/01/the-relationship-zoo/ Toujours un excellent article: une typologie des relations entre les objets.  http://www.joelonsoftware.com/articles/LeakyAbstractions.html Joel Spolsky : « All non-trivial abstractions, to some degree, are leaky. »  http://giorgiosironi.blogspot.com/2009/07/when-to-inject-distinction-between.html Injecter ou créer ?  http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/ Démontre le danger des singletons « cachés ». Peut être lue de la même façon comme un argument contre le ServiceLocator. Cela dit, à mon avis, le problème de fond est dans le fait d’utiliser des classes concrètes (CreditCard) au lieu d’abstractions (ICreditCard) qui sont de facto décorrélés de leurs implémentations. 70
  71. 71. 13 juillet 2013© Invenietis 2012-2013 Cycle de Vie: les deux approches  Le Container traque les instances (et leurs dépendances)  Il faut appeler une méthode explicite Release( o ) lorsque l’on ne se sert plus de o  C’est le mode « Rolls-Royce tout terrain » • Indépendant du type d’application • Si les développeurs ET l’infrastructure appellent correctement Release( o ) OU (souvent exclusif)  L’application gère ses « Scopes »  Moins de bookkeeping (donc d’overhead)  Particulièrement adapté au modèle Request/Response  Sensiblement couplé à un type d’application, un Host particulier  Lecture fortement recommandée:  http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/ 71

×