Injection de dependances - Les bases

71
13 juillet 2013 © Invenietis 2012-2013 Injection de Dépendances …les bases

Transcript of Injection de dependances - Les bases

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

Objets « Stateful » ou « Stateless »

Cycle de vie

Seam & Composition Root

2

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

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

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

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

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

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’utilise pas « new ».

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 ».

• J’ai un champ qui contient le D à utiliser.

• Je n’ai pas de champ pour D.

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.• 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

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 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

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

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

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

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

???

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

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

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

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

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

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.

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

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”.

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

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

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

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

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:\Temp\GoogleHomeDownloaded.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();

}}

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

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

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

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.

ParameterInjection

ContructorInjection

MethodInjection

PropertyInjection

34

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

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

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

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

13 juillet 2013© Invenietis 2012-2013

Programming to Abstractions Qui décide des implémentations ?

class C : IC{public C( ID dep ) { ... }

}

39

?

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

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

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

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

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

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

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

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" );

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 ) );

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

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 »

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

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

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

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

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();// Registerc.RegisterType<IA, A>( new ContainerControlledLifetimeManager() );// Resolvevar a = c.Resolve<IA>();a.DoSomething();

}}

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…

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

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

ConceptionPas de Container de DI Container de DI

Pas de DICouplage fort, problématiquestechniques (constructions, cycle de vie) intriquées avec le Métier.

Service Locator Anti-Pattern. Dépendances invisibles, difficile à maintenir.

DICodage à la main de l’obtention/instanciation des dépendances.

De nombreux bénéfices associés.

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.

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.

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…

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

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 !

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

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

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

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>();

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

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

13 juillet 2013© Invenietis 2012-2013

Bibliographie “Dependency Injection in .Net’, Mark Seeman, Manning 2012

http://www.martinfowler.com/articles/injection.htmlUn must-read…

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.htmlhttp://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.htmlJoel Spolsky : « All non-trivial abstractions, to some degree, are leaky. »

http://giorgiosironi.blogspot.com/2009/07/when-to-inject-distinction-between.htmlInjecter 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

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