Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas...

55
Page 1 Réutilisabilité du code Réutilisabilité du code IT&L@bs CO PMM Version 1.01, le 29 novembre 2012 Nicolas Le Nardou Architecte / Expert Technique PHP [email protected]

Transcript of Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas...

Page 1: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Page 1Réutilisabilité du code

Réutilisabilité du codeIT&L@bsCO PMMVersion 1.01, le 29 novembre 2012 Nicolas Le Nardou

Architecte / Expert Technique PHP

[email protected]

Page 2: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Introduction : contexte projet

> Centre de services d’un grand groupe de presse

> 20-30 sites en PHP- eZ Publish, Symfony 2, WordPress, from scratch, …

> Forte audience : environ 10M de pages vues / jour

Page 2Réutilisabilité du code

> Forte audience : environ 10M de pages vues / jour

> Périmètres fonctionnels très proches

> Pression sur les coûts de développement

Page 3: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Introduction : contexte projet

> A son écriture, le partage du code entre plusieurs sites est :- Soit déjà acté- Soit déjà en cours de discussion

> Le partage avec les autres sites du CDS est toujours de l’ordre du possible

Page 3Réutilisabilité du code

Page 4: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Introduction : problématique

> Comment se construire un référentiel de code commun à tous nos sites ?- Quel que soit le socle technique- Sans renoncer aux apports de ces différents socles (pas de politique du

plus petit dénominateur commun)

> Objectifs :

Page 4Réutilisabilité du code

> Objectifs :- Mutualiser la maintenance du code- Réduire les temps de développement

Page 5: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

sommaire

> 1 – Rappel des principes de conception SOLID

> 2 – Etude de cas concrets

> 3 – Point sur les tests unitaires

Page 5Réutilisabilité du code

> 3 – Point sur les tests unitaires

Page 6: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Conception SOLID

Rappel

Réutilisabilité du code

Page 7: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

conception SOLID

> Single Responsibility

> Open / Closed

> Liskov substitution

Page 7Réutilisabilité du code

> Interface segregation

> Dependency injection

Page 8: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID vs STUPID

> Singleton

> Tight coupling

> Untestability

Page 8Réutilisabilité du code

> Premature Optimization

> Indescriptive Naming

> Duplication

Page 9: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID : single responsibility

> Principe de responsabilité unique :> « Une classe ne fait qu’une et une seule chose »

> Envie de rajouter une fonctionnalité ? Il est temps de créer une nouvelle classe.

Page 9Réutilisabilité du code

> Une classe au fonctionnement clairement défini et borné sera plus facilement réutilisable

> Une classe aux multiples responsabilités sera fatalement dupliquée pour être adaptée au nouveau besoin

Page 10: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID : open / closed

> « Une classe doit être fermée à la modification et ouverte à l’extension »

> Une évolution ne devrait pas vous faire casser du code, juste en ajouter !

Page 10Réutilisabilité du code

> Une classe doit prévoir de pouvoir être étendue sans être réécrite.

Page 11: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID : Liskov substitution

> « On doit pouvoir substituer à un objet d’une classe X, tout objet d’une sous classe de X »

> Corolaire : Une classe utilisant un objet de classe X ne doit pas avoir connaissance des sous classes de X (sous peine de violer le principe open/closed)

Page 11Réutilisabilité du code

Page 12: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID : Interface segregation

> « Un objet ne devra pas dépendre d’un autre objet mais de son interface »

> Il faut expliciter la dépendance réelle au travers d’une interface

Page 12Réutilisabilité du code

Page 13: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

SOLID : Dependency Injection

> « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur »

> Inversion de contrôle

> Pas d’utilisation du mot clé new dans une classe

Page 13Réutilisabilité du code

> Pas d’utilisation du mot clé new dans une classe

> Injection par constructeur ou mutateur

Page 14: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Cas concret #1

Réutilisabilité du code

Page 15: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1

> Besoin : Injecter dans nos pages des tags javascript (tracking, pub, …)

> Implémentation : Une classe TagServer qui calcule la valeur d’un tag en fonction d’un contexte en entrée (url, contenu, …) et d’un jeu de règles

Page 15Réutilisabilité du code

- Moteur de règles- Jeu de règles en configuration

> Contrainte : A déployer sur :1. Un site eZ Publish2. Un site Symfony 2.x

Page 16: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1

> Les mauvaises solutions :

- Faire 2 développements distincts

- Dupliquer la classe et la modifier

Page 16Réutilisabilité du code

- Nombreux paramètres dans le constructeur

- Ou toute autre abomination …

Page 17: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : implémentation eZ Publish

class TagServer

{

private

$rules ;

public function __construct()

{

Page 17Réutilisabilité du code

{

$this-> rules = array ();

$ini = eZINI:: instance( 'tagserver.ini' );

$ini->assign( 'Tags' , 'Rules' , $this-> rules );

}

// ...

}

Page 18: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : problèmes

public function __construct()

{

$this-> rules = array ();

$ini = eZINI:: instance('tagserver.ini');

$ini->assign( 'Tags' , 'Rules' , $this-> rules );

Page 18Réutilisabilité du code

> Couplage fort : TagServer dépend de eZINI

� La classe n’est réutilisable que sur un autre site eZ Publish �

}

Page 19: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : problèmes

> Solution : injecter l’objet eZINI dans le constructeur

> On pourra ainsi substituer à une occurrence d’eZINI, un objet d’une

Injection de dépendances (SOLID)

Page 19Réutilisabilité du code

> On pourra ainsi substituer à une occurrence d’eZINI, un objet d’une sous classe d’eZINI

Page 20: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : eZINI injecté

class TagServer

{

private

$rules ;

public function __construct(eZINI $ini )

{

Page 20Réutilisabilité du code

{

$this-> rules = array ();

$ini ->assign( 'Tags' , 'Rules' , $this-> rules );

}

// ...

}

Page 21: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : eZINI injecté

$ini = eZINI:: instance( 'tagserver.ini' );

$server = new TagServer($ini);

> La construction du serveur :

Page 21Réutilisabilité du code

Page 22: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : eZINI injecté

> Couplage désormais faible

> Mais problème de sémantique : conceptuellement nous n’avons pas besoin d’un eZINI, nous avons plutôt besoin de la configuration.

� Il nous faut une interface « Configuration »

Page 22Réutilisabilité du code

� Il nous faut une interface « Configuration »

Séparation d’interfaces (SOLID)

Page 23: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : interface Configuration

interface Configuration

{

const SEPARATOR = '/' ;

/**

* Read configuration if exists. Returns default value

* otherwise .

Page 23Réutilisabilité du code

* otherwise .

*

* @param string $variableName fully qualified variable name

* @param mixed $defaultValue

*/

public function read( $variableName , $defaultValue );

}

Page 24: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : interface Configuration

class TagServer

{

private

$rules ;

public function __construct(Configuration $config )

{

Page 24Réutilisabilité du code

{

$this-> rules = $configuration ->read(

'tagserver/Tags/Rules' ,

array ()

);

}

}

Page 25: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : interface Configuration

> La dépendance avec le framework d’eZ Publish est rompue …> … mais notre code ne fonctionne plus pour eZ Publish

> Il nous faut une implémentation de Configuration reposant sur eZINI

Substitution de Liskov (SOLID)

Page 25Réutilisabilité du code

Page 26: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : eZConfiguration

class eZConfiguration implements Configuration

{

public function read( $variableName , $defaultValue )

{

list ($file, $group, $variable) =

explode( self :: SEPARATOR, $variableName );

Page 26Réutilisabilité du code

$ini = eZINI:: instance($file . '.ini' );

$ini->assign($group, $variable, $defaultValue );

return $defaultValue ;

}

}

Page 27: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : eZConfiguration

> Appel

$configuration = new eZConfiguration();

$server = new TagServer($configuration);

> Fonctionne à nouveau pour eZ Publish

Page 27Réutilisabilité du code

> Fonctionne à nouveau pour eZ Publish- Sans modification de la classe TagServer

Open / Closed (SOLID)

Page 28: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : site Symfony

> Etape suivante : réutiliser notre classe TagServer sur un site reposant sur Symfony

Page 28Réutilisabilité du code

Page 29: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : site Symfony

> Bien sûr, la classe eZConfiguration ne fonctionnera pas

> Il nous faut une classe YamlConfiguration

Page 29Réutilisabilité du code

Page 30: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : site Symfony

class YamlConfiguration implements Configuration{

public function read( $variableName , $defaultValue ){

list ($file, $group, $variable) = explode( self :: SEPARATOR, $variableName );

Page 30Réutilisabilité du code

$loader = Yaml:: parse($file);if (array_key_exists($loader[$group][$variable])){

return $loader[$group][$variable];}

return $defaultValue ;}

}

Page 31: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : site Symfony

> Construction du serveur :

> Et …. c’est tout !

$configuration = new YamlConfiguration();$server = new TagServer($configuration);

Page 31Réutilisabilité du code

> Et …. c’est tout !

Page 32: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #1 : bilan

> Coût du déploiement de notre classe TagServer sur un autre framework PHP

Coût de développement d’une classe d’adaptation pour accéder à la configuration

Page 32Réutilisabilité du code

> Aucune modification de notre classe TagServer n’a été nécessaire> Les classes de la couche d’adaptation sont elles-mêmes

réutilisables � constitution d’une boîte à outils très rapidement

Page 33: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Cas concret #2

Réutilisabilité du code

Page 34: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2

> Nous voulons ajouter des logs à notre classe TagServer

> Contraintes :- Possibilité de les activer / désactiver- Possibilité de se reposer sur le système de log du socle technique utilisé

Page 34Réutilisabilité du code

Page 35: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2

class TagServer

{

private

$logger ;

public function __construct(Logger $logger )

{

Page 35Réutilisabilité du code

{

$this-> logger = $logger ;

}

}

Page 36: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : empilement de paramètres

class TagServer

{

private

$rules ,

$logger ;

public function __construct(Configuration $configuration , Logger $logger )

{

Page 36Réutilisabilité du code

{

$this-> logger = $logger ;

$this-> rules = $configuration ->read(

'tagserver/Tags/Rules' ,

array ()

);

}

}

Page 37: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : dépendance faible

> Contrairement à la configuration, le logger est une dépendance faible

> Un logger n’est pas requis pour le fonctionnement de notre classe

Page 37Réutilisabilité du code

� Injection par mutateur

Page 38: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : injection par mutateur

class TagServer

{

private

$logger ;

public function __construct(Configuration $configuration )

{

$this - >logger = null ;

Page 38Réutilisabilité du code

$this - >logger = null ;

/* ... */

}

public function setLogger(Logger $logger )

{

$this-> logger = $logger ;

return $this;

}

}

Page 39: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : injection par mutateur

private function writeLog( $message )

{

if ($this-> logger !== null )

{

$this-> logger ->write( $message );

}

}

Page 39Réutilisabilité du code

> Et l’appel :

$server = new TagServer( new eZConfiguration());

$server->setLogger( new eZLogger());

Page 40: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : overhead

> Les cas présentés sont simples et petits

> A dimension d’un projet réel, les overheads de code pour construire les objets peuvent devenir pénibles à gérer.

> Par exemple, il a fort à parier que le logger soit nécessaire sur de

Page 40Réutilisabilité du code

> Par exemple, il a fort à parier que le logger soit nécessaire sur de nombreuses classes.

Page 41: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur d’injection

> Solution : recours à un conteneur d’injection

> Pimple (Sensio Labs)> DI Component de Symfony (Sensio Labs)

Page 41Réutilisabilité du code

> Objet en charge de l’instanciation des autres objets

Page 42: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur commun

abstract class Container extends Pimple{

public function __construct(){

$this[ 'tagServer' ] = function ($container){

$server = new TagServer($container[ 'configuration' ]);

Page 42Réutilisabilité du code

$server->setLogger($container[ 'logger' ]);

return $server;};

}}

Page 43: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur d’injection

Conteneur commun

Page 43Réutilisabilité du code

Conteneur communà tous les socles techniques

Conteneurs spécifiques

Page 44: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur spécifique (eZ Publish)

class eZContainer extends Container{

public function __construct(){

parent ::__construct();

$this[ 'configuration' ] = function ($container){return new eZConfiguration();

Page 44Réutilisabilité du code

return new eZConfiguration();};

$this[ 'logger' ] = $this->share( function ($container){return new eZLogger();

});

}}

Page 45: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur d’injection

> Et la construction de notre classe :

$container = new eZContainer();$server = $container[ ' tagServer ' ];

Page 45Réutilisabilité du code

Page 46: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

cas concret #2 : conteneur d’injection

> Quelques remarques :

- Le conteneur peut s’appuyer sur de la configuration (ex: Symfony)

- Risque de dépendance au conteneur + global state

Page 46Réutilisabilité du code

- Dépendances masquées : quid des outils d’analyse ?

Page 47: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

Et si on testait ?

Réutilisabilité du code

Page 48: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : souvenez-vous

class TagServer

{

private

$rules ;

public function __construct()

{

Page 48Réutilisabilité du code

{

$this-> rules = array ();

$ini = eZINI:: instance( 'tagserver.ini' );

$ini->assign( 'Tags' , 'Rules' , $this-> rules );

}

// ...

}

Page 49: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : problématique

> Une instance eZ Publish est nécessaire� Problème de performances des tests

> Un fichier eZINI est également nécessaire� Eparpillement du code de test� Maintenabilité affaiblie

Page 49Réutilisabilité du code

> Et si eZINI était un service à bouchonner ? (comme la db, un webservice ou le filesystem)

Page 50: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : ArrayConfiguration

> Il faut mocker la configuration ���� ArrayConfiguration !

Page 50Réutilisabilité du code

Page 51: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : ArrayConfiguration

class ArrayConfiguration implements Configuration

{

private $values ;

public function __construct( array $values )

{

$this-> values = $values ;

}

Page 51Réutilisabilité du code

public function read( $variableName , $defaultValue )

{

if (array_key_exists( $variableName , $this-> values ))

{

return $this-> values [ $variableName ];

}

return $defaultValue ;

}

}

Page 52: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : le test unitaire

class TagServerTest extends PHPUnit_Framework_TestCase

{

private

$tagServer ;

public function setUp()

{

Page 52Réutilisabilité du code

{

$configuration = new ArrayConfiguration( array (

'tagserver/Tags/Rules' => array ( /* ... */ )

));

$this-> tagServer = new TagServer($configuration);

}

}

Page 53: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

testabilité : bilan

> C’est testable !

> C’est performant !

> Le test est facile à maintenir !

Page 53Réutilisabilité du code

> Possibilité de tester aussi les cas à la marge : - Configuration manquante- Configuration erronée- Configuration non consistante- …

Page 54: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

merci!

Page 54Réutilisabilité du code

Page 55: Reutilisabilite du code - callmematthi.eu · SOLID : Dependency Injection > « Un objet ne doit pas instancier un autre objet, il doit le recevoir de l’extérieur » > Inversion

si vous avez des questions ?

Page 55Réutilisabilité du code

Nicolas Le NardouArchitecte / Expert Technique PHP

[email protected]