SlideShare ist ein Scribd-Unternehmen logo
1 von 55
Réutilisabilité du code
IT&L@bs
CO PMM
Version 1.01, le 29 novembre 2012             Nicolas Le Nardou
                                              Architecte / Expert Technique PHP

                                              nicolas.lenardou@orange.com
           Réutilisabilité du code   Page 1
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

> Périmètres fonctionnels très proches

> Pression sur les coûts de développement




     Réutilisabilité du code      Page 2
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




     Réutilisabilité du code         Page 3
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 :
   - Mutualiser la maintenance du code
   - Réduire les temps de développement




     Réutilisabilité du code        Page 4
sommaire


> 1 – Rappel des principes de conception SOLID

> 2 – Etude de cas concrets

> 3 – Point sur les tests unitaires




     Réutilisabilité du code      Page 5
Conception SOLID
Rappel




     Réutilisabilité du code
conception SOLID

> Single Responsibility

> Open / Closed

> Liskov substitution

> Interface segregation

> Dependency injection




     Réutilisabilité du code   Page 7
SOLID vs STUPID

> Singleton

> Tight coupling

> Untestability

> Premature Optimization

> Indescriptive Naming

> Duplication



     Réutilisabilité du code   Page 8
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.

> 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




     Réutilisabilité du code     Page 9
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 !

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




     Réutilisabilité du code     Page 10
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)




     Réutilisabilité du code     Page 11
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




     Réutilisabilité du code      Page 12
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


> Injection par constructeur ou mutateur




      Réutilisabilité du code     Page 13
Cas concret #1




    Réutilisabilité du code
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
    - Moteur de règles
    - Jeu de règles en configuration


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




         Réutilisabilité du code       Page 15
cas concret #1

> Les mauvaises solutions :

   - Faire 2 développements distincts

   - Dupliquer la classe et la modifier

   - Nombreux paramètres dans le constructeur

   - Ou toute autre abomination …




     Réutilisabilité du code         Page 16
cas concret #1 : implémentation eZ Publish

class TagServer
{
    private
        $rules;

    public function __construct()
    {
        $this->rules = array();

            $ini = eZINI::instance('tagserver.ini');
            $ini->assign('Tags', 'Rules', $this->rules);
    }

    // ...
}

        Réutilisabilité du code   Page 17
cas concret #1 : problèmes

public function __construct()
{
        $this->rules = array();

           $ini = eZINI::instance('tagserver.ini');
           $ini->assign('Tags', 'Rules', $this->rules);
}




> Couplage fort : TagServer dépend de eZINI

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



     Réutilisabilité du code          Page 18
cas concret #1 : problèmes

> Solution : injecter l’objet eZINI dans le constructeur

                                            Injection de dépendances (SOLID)




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




     Réutilisabilité du code      Page 19
cas concret #1 : eZINI injecté

class TagServer
{
    private
        $rules;

    public function __construct(eZINI $ini)
    {
        $this->rules = array();

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

    // ...
}



        Réutilisabilité du code   Page 20
cas concret #1 : eZINI injecté

> La construction du serveur :


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




     Réutilisabilité du code     Page 21
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 »

                                           Séparation d’interfaces (SOLID)




     Réutilisabilité du code     Page 22
cas concret #1 : interface Configuration

interface Configuration
{
    const SEPARATOR = '/';

    /**
     * Read configuration if exists. Returns default value
     * otherwise.
     *
     * @param string $variableName fully qualified variable name
     * @param mixed $defaultValue
     */
    public function read($variableName, $defaultValue);
}




     Réutilisabilité du code   Page 23
cas concret #1 : interface Configuration

class TagServer
{
    private
        $rules;

    public function __construct(Configuration $config)
    {
        $this->rules = $configuration->read(
            'tagserver/Tags/Rules',
            array()
        );
    }
}




     Réutilisabilité du code   Page 24
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)




     Réutilisabilité du code    Page 25
cas concret #1 : eZConfiguration

class eZConfiguration implements Configuration
{
    public function read($variableName, $defaultValue)
    {
        list($file, $group, $variable) =
                        explode(self::SEPARATOR, $variableName);

            $ini = eZINI::instance($file . '.ini');
            $ini->assign($group, $variable, $defaultValue);

            return $defaultValue;
    }
}




        Réutilisabilité du code     Page 26
cas concret #1 : eZConfiguration

> Appel

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



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

                                                Open / Closed (SOLID)




     Réutilisabilité du code       Page 27
cas concret #1 : site Symfony

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




     Réutilisabilité du code     Page 28
cas concret #1 : site Symfony

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

> Il nous faut une classe YamlConfiguration




     Réutilisabilité du code    Page 29
cas concret #1 : site Symfony

class YamlConfiguration implements Configuration
{

    public function read($variableName, $defaultValue)
    {
        list($file, $group, $variable) =
                            explode(self::SEPARATOR, $variableName);

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

           return $defaultValue;
    }

}

        Réutilisabilité du code    Page 30
cas concret #1 : site Symfony

> Construction du serveur :

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



> Et …. c’est tout !




     Réutilisabilité du code   Page 31
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



> 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



     Réutilisabilité du code          Page 32
Cas concret #2




    Réutilisabilité du code
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é




     Réutilisabilité du code         Page 34
cas concret #2

class TagServer
{
    private
        $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }
}




     Réutilisabilité du code   Page 35
cas concret #2 : empilement de paramètres

class TagServer
{
    private
        $rules,
        $logger;

    public function __construct(Configuration $configuration, Logger $logger)
    {
        $this->logger = $logger;

        $this->rules = $configuration->read(
            'tagserver/Tags/Rules',
            array()
        );
    }
}



        Réutilisabilité du code     Page 36
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



  Injection par mutateur




     Réutilisabilité du code    Page 37
cas concret #2 : injection par mutateur

class TagServer
{
    private
        $logger;

    public function __construct(Configuration $configuration)
    {
        $this->logger = null;
        /* ... */
    }

    public function setLogger(Logger $logger)
    {
        $this->logger = $logger;

           return $this;
    }
}
        Réutilisabilité du code   Page 38
cas concret #2 : injection par mutateur

    private function writeLog($message)
    {
        if($this->logger !== null)
        {
            $this->logger->write($message);
        }
    }


> Et l’appel :

$server = new TagServer(new eZConfiguration());
$server->setLogger(new eZLogger());




     Réutilisabilité du code     Page 39
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
  nombreuses classes.




     Réutilisabilité du code      Page 40
cas concret #2 : conteneur d’injection

> Solution : recours à un conteneur d’injection

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



> Objet en charge de l’instanciation des autres objets




     Réutilisabilité du code     Page 41
cas concret #2 : conteneur commun

abstract class Container extends Pimple
{
    public function __construct()
    {
        $this['tagServer'] = function ($container){

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

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


                   return $server;
            };
    }
}




        Réutilisabilité du code      Page 42
cas concret #2 : conteneur d’injection




     Conteneur commun
 à tous les socles techniques




   Conteneurs spécifiques



    Réutilisabilité du code     Page 43
cas concret #2 : conteneur spécifique (eZ Publish)

class eZContainer extends Container
{
    public function __construct()
    {
        parent::__construct();

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

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

    }
}



        Réutilisabilité du code   Page 44
cas concret #2 : conteneur d’injection

> Et la construction de notre classe :

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




      Réutilisabilité du code     Page 45
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

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




     Réutilisabilité du code       Page 46
Et si on testait ?




     Réutilisabilité du code
testabilité : souvenez-vous

class TagServer
{
    private
        $rules;

    public function __construct()
    {
        $this->rules = array();

             $ini = eZINI::instance('tagserver.ini');
             $ini->assign('Tags', 'Rules', $this->rules);
    }

    // ...
}

        Réutilisabilité du code   Page 48
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



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




     Réutilisabilité du code          Page 49
testabilité : ArrayConfiguration

> Il faut mocker la configuration      ArrayConfiguration !




     Réutilisabilité du code        Page 50
testabilité : ArrayConfiguration

class ArrayConfiguration implements Configuration
{
    private $values;

    public function __construct(array $values)
    {
        $this->values = $values;
    }

    public function read($variableName, $defaultValue)
    {
        if(array_key_exists($variableName, $this->values))
        {
                 return $this->values[$variableName];
          }

          return $defaultValue;
    }
}
        Réutilisabilité du code         Page 51
testabilité : le test unitaire

class TagServerTest extends PHPUnit_Framework_TestCase
{
    private
        $tagServer;

    public function setUp()
    {
        $configuration = new ArrayConfiguration(array(
            'tagserver/Tags/Rules' => array(/* ... */)
        ));

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



        Réutilisabilité du code   Page 52
testabilité : bilan

> C’est testable !

> C’est performant !

> Le test est facile à maintenir !

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




        Réutilisabilité du code          Page 53
merci!




Réutilisabilité du code     Page 54
si vous avez des questions ?




                          Nicolas Le Nardou
                          Architecte / Expert Technique PHP

                          nicolas.lenardou@orange.com


Réutilisabilité du code                Page 55

Weitere ähnliche Inhalte

Was ist angesagt?

.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHPAbdoulaye Dieng
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debianyahyaf10
 
ZendFramework2 - Présentation
ZendFramework2 - PrésentationZendFramework2 - Présentation
ZendFramework2 - Présentationjulien pauli
 
Python avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementiellePython avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementielleECAM Brussels Engineering School
 
Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...ECAM Brussels Engineering School
 
Initiation au php
Initiation au phpInitiation au php
Initiation au phpStrasWeb
 
PHP 7 et Symfony 3
PHP 7 et Symfony 3PHP 7 et Symfony 3
PHP 7 et Symfony 3Eddy RICHARD
 
Notions de base de JavaScript
Notions de base de JavaScriptNotions de base de JavaScript
Notions de base de JavaScriptKristen Le Liboux
 

Was ist angesagt? (20)

Playing With PHP 5.3
Playing With PHP 5.3Playing With PHP 5.3
Playing With PHP 5.3
 
Gestion de formulaires en PHP
Gestion de formulaires en PHPGestion de formulaires en PHP
Gestion de formulaires en PHP
 
Introduction au Jquery
Introduction au JqueryIntroduction au Jquery
Introduction au Jquery
 
Configuration PHP5
Configuration PHP5Configuration PHP5
Configuration PHP5
 
Héritage et redéfinition de méthode
Héritage et redéfinition de méthodeHéritage et redéfinition de méthode
Héritage et redéfinition de méthode
 
Syntaxe du langage PHP
Syntaxe du langage PHPSyntaxe du langage PHP
Syntaxe du langage PHP
 
.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debian
 
ZendFramework2 - Présentation
ZendFramework2 - PrésentationZendFramework2 - Présentation
ZendFramework2 - Présentation
 
Cours php
Cours phpCours php
Cours php
 
Rapport tp openssl
Rapport  tp  opensslRapport  tp  openssl
Rapport tp openssl
 
Python avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementiellePython avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementielle
 
Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...Développement informatique : Programmation fonctionnelle, décorateur et génér...
Développement informatique : Programmation fonctionnelle, décorateur et génér...
 
Initiation au php
Initiation au phpInitiation au php
Initiation au php
 
Initiation au php
Initiation au phpInitiation au php
Initiation au php
 
PHP5 et les fichiers
PHP5 et les fichiersPHP5 et les fichiers
PHP5 et les fichiers
 
Python avancé : Lecture et écriture de fichiers
Python avancé : Lecture et écriture de fichiersPython avancé : Lecture et écriture de fichiers
Python avancé : Lecture et écriture de fichiers
 
PHP 7 et Symfony 3
PHP 7 et Symfony 3PHP 7 et Symfony 3
PHP 7 et Symfony 3
 
Nouveautés php 7
Nouveautés php 7Nouveautés php 7
Nouveautés php 7
 
Notions de base de JavaScript
Notions de base de JavaScriptNotions de base de JavaScript
Notions de base de JavaScript
 

Andere mochten auch

Solutions Linux 2010 - Maîtrise du développement PHP
Solutions Linux 2010 - Maîtrise du développement PHPSolutions Linux 2010 - Maîtrise du développement PHP
Solutions Linux 2010 - Maîtrise du développement PHPJean-Marc Fontaine
 
Agile tour Lille 2015 allies ensemble contre les defauts
Agile tour Lille 2015 allies ensemble contre les defautsAgile tour Lille 2015 allies ensemble contre les defauts
Agile tour Lille 2015 allies ensemble contre les defautsAntoine Blk
 
Wygday 2010 - architecture tfs et industrialisation
Wygday 2010 - architecture tfs et industrialisationWygday 2010 - architecture tfs et industrialisation
Wygday 2010 - architecture tfs et industrialisationWygwam
 
Formation Management Visuel & Efficacité Individuelle
Formation Management Visuel & Efficacité IndividuelleFormation Management Visuel & Efficacité Individuelle
Formation Management Visuel & Efficacité IndividuelleBernard JOUVEL
 
Agile france2015 agiliteformation
Agile france2015 agiliteformationAgile france2015 agiliteformation
Agile france2015 agiliteformationHoussam FAKIH
 
jQuery sans jQuery
jQuery sans jQueryjQuery sans jQuery
jQuery sans jQuerygoldoraf
 
Webperformance #rouendayvous
Webperformance #rouendayvousWebperformance #rouendayvous
Webperformance #rouendayvousOlivier MARTINEAU
 
Patchwork UTF-8 : portabilité unicode et graphèmes clusters
Patchwork UTF-8 : portabilité unicode et graphèmes clustersPatchwork UTF-8 : portabilité unicode et graphèmes clusters
Patchwork UTF-8 : portabilité unicode et graphèmes clustersnicolas.grekas
 
HTML5 mobile avec Sencha Touch [FR]
HTML5 mobile avec Sencha Touch [FR]HTML5 mobile avec Sencha Touch [FR]
HTML5 mobile avec Sencha Touch [FR]Wixiweb
 
Livraison et intégration continue avec TFS 2013 et InRelease
Livraison et intégration continue avec TFS 2013 et InReleaseLivraison et intégration continue avec TFS 2013 et InRelease
Livraison et intégration continue avec TFS 2013 et InReleaseMicrosoft
 
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineLa qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineInterface ULg, LIEGE science park
 
Breizhcamp 2014 : Une partie de Cache-Cache
Breizhcamp 2014 : Une partie de Cache-CacheBreizhcamp 2014 : Une partie de Cache-Cache
Breizhcamp 2014 : Une partie de Cache-CacheFrederic Bouchery
 
L'agilité en entreprise avec TFS 2013
L'agilité en entreprise avec TFS 2013L'agilité en entreprise avec TFS 2013
L'agilité en entreprise avec TFS 2013Microsoft
 
Le Profiling d'applications PHP - Blackfire.io
Le Profiling d'applications PHP - Blackfire.ioLe Profiling d'applications PHP - Blackfire.io
Le Profiling d'applications PHP - Blackfire.ionicolas.grekas
 
PHP Tour 2012 - Conférence FuelPHP
PHP Tour 2012 - Conférence FuelPHPPHP Tour 2012 - Conférence FuelPHP
PHP Tour 2012 - Conférence FuelPHPNovius OS
 
Falling in Love with Forms [Microsoft Edge Web Summit 2015]
Falling in Love with Forms [Microsoft Edge Web Summit 2015]Falling in Love with Forms [Microsoft Edge Web Summit 2015]
Falling in Love with Forms [Microsoft Edge Web Summit 2015]Aaron Gustafson
 
Elasticsearch - OSDC France 2012
Elasticsearch - OSDC France 2012Elasticsearch - OSDC France 2012
Elasticsearch - OSDC France 2012David Pilato
 
Maitriser les structures de données PHP 102 - Forum Paris 2012
Maitriser les structures de données PHP 102 - Forum Paris 2012Maitriser les structures de données PHP 102 - Forum Paris 2012
Maitriser les structures de données PHP 102 - Forum Paris 2012Patrick Allaert
 
Behat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatBehat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatSamuel ROZE
 

Andere mochten auch (20)

Solutions Linux 2010 - Maîtrise du développement PHP
Solutions Linux 2010 - Maîtrise du développement PHPSolutions Linux 2010 - Maîtrise du développement PHP
Solutions Linux 2010 - Maîtrise du développement PHP
 
Agile tour Lille 2015 allies ensemble contre les defauts
Agile tour Lille 2015 allies ensemble contre les defautsAgile tour Lille 2015 allies ensemble contre les defauts
Agile tour Lille 2015 allies ensemble contre les defauts
 
Wygday 2010 - architecture tfs et industrialisation
Wygday 2010 - architecture tfs et industrialisationWygday 2010 - architecture tfs et industrialisation
Wygday 2010 - architecture tfs et industrialisation
 
Formation Management Visuel & Efficacité Individuelle
Formation Management Visuel & Efficacité IndividuelleFormation Management Visuel & Efficacité Individuelle
Formation Management Visuel & Efficacité Individuelle
 
Agile france2015 agiliteformation
Agile france2015 agiliteformationAgile france2015 agiliteformation
Agile france2015 agiliteformation
 
jQuery sans jQuery
jQuery sans jQueryjQuery sans jQuery
jQuery sans jQuery
 
Webperformance #rouendayvous
Webperformance #rouendayvousWebperformance #rouendayvous
Webperformance #rouendayvous
 
Patchwork UTF-8 : portabilité unicode et graphèmes clusters
Patchwork UTF-8 : portabilité unicode et graphèmes clustersPatchwork UTF-8 : portabilité unicode et graphèmes clusters
Patchwork UTF-8 : portabilité unicode et graphèmes clusters
 
HTML5 mobile avec Sencha Touch [FR]
HTML5 mobile avec Sencha Touch [FR]HTML5 mobile avec Sencha Touch [FR]
HTML5 mobile avec Sencha Touch [FR]
 
Livraison et intégration continue avec TFS 2013 et InRelease
Livraison et intégration continue avec TFS 2013 et InReleaseLivraison et intégration continue avec TFS 2013 et InRelease
Livraison et intégration continue avec TFS 2013 et InRelease
 
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineLa qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
 
Breizhcamp 2014 : Une partie de Cache-Cache
Breizhcamp 2014 : Une partie de Cache-CacheBreizhcamp 2014 : Une partie de Cache-Cache
Breizhcamp 2014 : Une partie de Cache-Cache
 
L'agilité en entreprise avec TFS 2013
L'agilité en entreprise avec TFS 2013L'agilité en entreprise avec TFS 2013
L'agilité en entreprise avec TFS 2013
 
Le Profiling d'applications PHP - Blackfire.io
Le Profiling d'applications PHP - Blackfire.ioLe Profiling d'applications PHP - Blackfire.io
Le Profiling d'applications PHP - Blackfire.io
 
PHP Tour 2012 - Conférence FuelPHP
PHP Tour 2012 - Conférence FuelPHPPHP Tour 2012 - Conférence FuelPHP
PHP Tour 2012 - Conférence FuelPHP
 
Falling in Love with Forms [Microsoft Edge Web Summit 2015]
Falling in Love with Forms [Microsoft Edge Web Summit 2015]Falling in Love with Forms [Microsoft Edge Web Summit 2015]
Falling in Love with Forms [Microsoft Edge Web Summit 2015]
 
Elasticsearch - OSDC France 2012
Elasticsearch - OSDC France 2012Elasticsearch - OSDC France 2012
Elasticsearch - OSDC France 2012
 
Maitriser les structures de données PHP 102 - Forum Paris 2012
Maitriser les structures de données PHP 102 - Forum Paris 2012Maitriser les structures de données PHP 102 - Forum Paris 2012
Maitriser les structures de données PHP 102 - Forum Paris 2012
 
Management 3.0 motivators
Management 3.0   motivatorsManagement 3.0   motivators
Management 3.0 motivators
 
Behat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatBehat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than that
 

Ähnlich wie Réutilisabilité du code PHP

Introduction à Zend Framework 2
Introduction à Zend Framework 2Introduction à Zend Framework 2
Introduction à Zend Framework 2Mickael Perraud
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logiciellecyrilgandon
 
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...Paris Open Source Summit
 
Afup 2015 zf3 le futur de php
Afup 2015   zf3 le futur de phpAfup 2015   zf3 le futur de php
Afup 2015 zf3 le futur de phpSophie Beaupuis
 
Dotnet csharp
Dotnet csharpDotnet csharp
Dotnet csharpSDFG5
 
Soutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonySoutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonyVincent Composieux
 
SOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applicationsSOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applicationsVladyslav Riabchenko
 
Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Jean-Michel Doudoux
 
Utiliser le Zend Framework avec Symfony
Utiliser le Zend Framework avec SymfonyUtiliser le Zend Framework avec Symfony
Utiliser le Zend Framework avec SymfonyXavier Gorse
 
Présentation CoreOS
Présentation CoreOSPrésentation CoreOS
Présentation CoreOSgcatt
 
Annotations pour les Geeks
Annotations pour les GeeksAnnotations pour les Geeks
Annotations pour les Geeksjviet
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2Hugo Hamon
 
Spring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'tsSpring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'tsJulien Wittouck
 
Apache flink - prise en main rapide
Apache flink - prise en main rapideApache flink - prise en main rapide
Apache flink - prise en main rapideBilal Baltagi
 
Voxxeddays lux 2018 apres java 8, java 9 et 10
Voxxeddays lux 2018 apres java 8, java 9 et 10Voxxeddays lux 2018 apres java 8, java 9 et 10
Voxxeddays lux 2018 apres java 8, java 9 et 10Jean-Michel Doudoux
 
L’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacketL’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacketStéphane Legrand
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016Antoine Rey
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinLudovic Piot
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide
 

Ähnlich wie Réutilisabilité du code PHP (20)

Introduction à Zend Framework 2
Introduction à Zend Framework 2Introduction à Zend Framework 2
Introduction à Zend Framework 2
 
Zf2 ce-qui-va-changer
Zf2 ce-qui-va-changerZf2 ce-qui-va-changer
Zf2 ce-qui-va-changer
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
 
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...
#OSSPARIS17 - Docker Under the Hood : Networking & Loadbalancing & security m...
 
Afup 2015 zf3 le futur de php
Afup 2015   zf3 le futur de phpAfup 2015   zf3 le futur de php
Afup 2015 zf3 le futur de php
 
Dotnet csharp
Dotnet csharpDotnet csharp
Dotnet csharp
 
Soutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonySoutenance Zend Framework vs Symfony
Soutenance Zend Framework vs Symfony
 
SOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applicationsSOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applications
 
Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017
 
Utiliser le Zend Framework avec Symfony
Utiliser le Zend Framework avec SymfonyUtiliser le Zend Framework avec Symfony
Utiliser le Zend Framework avec Symfony
 
Présentation CoreOS
Présentation CoreOSPrésentation CoreOS
Présentation CoreOS
 
Annotations pour les Geeks
Annotations pour les GeeksAnnotations pour les Geeks
Annotations pour les Geeks
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Spring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'tsSpring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'ts
 
Apache flink - prise en main rapide
Apache flink - prise en main rapideApache flink - prise en main rapide
Apache flink - prise en main rapide
 
Voxxeddays lux 2018 apres java 8, java 9 et 10
Voxxeddays lux 2018 apres java 8, java 9 et 10Voxxeddays lux 2018 apres java 8, java 9 et 10
Voxxeddays lux 2018 apres java 8, java 9 et 10
 
L’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacketL’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacket
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
 
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassinOxalide Workshop #4 - Docker, des tours dans le petit bassin
Oxalide Workshop #4 - Docker, des tours dans le petit bassin
 

Réutilisabilité du code PHP

  • 1. Réutilisabilité du code IT&L@bs CO PMM Version 1.01, le 29 novembre 2012 Nicolas Le Nardou Architecte / Expert Technique PHP nicolas.lenardou@orange.com Réutilisabilité du code Page 1
  • 2. 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 > Périmètres fonctionnels très proches > Pression sur les coûts de développement Réutilisabilité du code Page 2
  • 3. 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 Réutilisabilité du code Page 3
  • 4. 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 : - Mutualiser la maintenance du code - Réduire les temps de développement Réutilisabilité du code Page 4
  • 5. sommaire > 1 – Rappel des principes de conception SOLID > 2 – Etude de cas concrets > 3 – Point sur les tests unitaires Réutilisabilité du code Page 5
  • 6. Conception SOLID Rappel Réutilisabilité du code
  • 7. conception SOLID > Single Responsibility > Open / Closed > Liskov substitution > Interface segregation > Dependency injection Réutilisabilité du code Page 7
  • 8. SOLID vs STUPID > Singleton > Tight coupling > Untestability > Premature Optimization > Indescriptive Naming > Duplication Réutilisabilité du code Page 8
  • 9. 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. > 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 Réutilisabilité du code Page 9
  • 10. 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 ! > Une classe doit prévoir de pouvoir être étendue sans être réécrite. Réutilisabilité du code Page 10
  • 11. 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) Réutilisabilité du code Page 11
  • 12. 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 Réutilisabilité du code Page 12
  • 13. 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 > Injection par constructeur ou mutateur Réutilisabilité du code Page 13
  • 14. Cas concret #1 Réutilisabilité du code
  • 15. 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 - Moteur de règles - Jeu de règles en configuration > Contrainte : A déployer sur : 1. Un site eZ Publish 2. Un site Symfony 2.x Réutilisabilité du code Page 15
  • 16. cas concret #1 > Les mauvaises solutions : - Faire 2 développements distincts - Dupliquer la classe et la modifier - Nombreux paramètres dans le constructeur - Ou toute autre abomination … Réutilisabilité du code Page 16
  • 17. cas concret #1 : implémentation eZ Publish class TagServer { private $rules; public function __construct() { $this->rules = array(); $ini = eZINI::instance('tagserver.ini'); $ini->assign('Tags', 'Rules', $this->rules); } // ... } Réutilisabilité du code Page 17
  • 18. cas concret #1 : problèmes public function __construct() { $this->rules = array(); $ini = eZINI::instance('tagserver.ini'); $ini->assign('Tags', 'Rules', $this->rules); } > Couplage fort : TagServer dépend de eZINI La classe n’est réutilisable que sur un autre site eZ Publish Réutilisabilité du code Page 18
  • 19. cas concret #1 : problèmes > Solution : injecter l’objet eZINI dans le constructeur Injection de dépendances (SOLID) > On pourra ainsi substituer à une occurrence d’eZINI, un objet d’une sous classe d’eZINI Réutilisabilité du code Page 19
  • 20. cas concret #1 : eZINI injecté class TagServer { private $rules; public function __construct(eZINI $ini) { $this->rules = array(); $ini->assign('Tags', 'Rules', $this->rules); } // ... } Réutilisabilité du code Page 20
  • 21. cas concret #1 : eZINI injecté > La construction du serveur : $ini = eZINI::instance('tagserver.ini'); $server = new TagServer($ini); Réutilisabilité du code Page 21
  • 22. 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 » Séparation d’interfaces (SOLID) Réutilisabilité du code Page 22
  • 23. cas concret #1 : interface Configuration interface Configuration { const SEPARATOR = '/'; /** * Read configuration if exists. Returns default value * otherwise. * * @param string $variableName fully qualified variable name * @param mixed $defaultValue */ public function read($variableName, $defaultValue); } Réutilisabilité du code Page 23
  • 24. cas concret #1 : interface Configuration class TagServer { private $rules; public function __construct(Configuration $config) { $this->rules = $configuration->read( 'tagserver/Tags/Rules', array() ); } } Réutilisabilité du code Page 24
  • 25. 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) Réutilisabilité du code Page 25
  • 26. cas concret #1 : eZConfiguration class eZConfiguration implements Configuration { public function read($variableName, $defaultValue) { list($file, $group, $variable) = explode(self::SEPARATOR, $variableName); $ini = eZINI::instance($file . '.ini'); $ini->assign($group, $variable, $defaultValue); return $defaultValue; } } Réutilisabilité du code Page 26
  • 27. cas concret #1 : eZConfiguration > Appel $configuration = new eZConfiguration(); $server = new TagServer($configuration); > Fonctionne à nouveau pour eZ Publish - Sans modification de la classe TagServer Open / Closed (SOLID) Réutilisabilité du code Page 27
  • 28. cas concret #1 : site Symfony > Etape suivante : réutiliser notre classe TagServer sur un site reposant sur Symfony Réutilisabilité du code Page 28
  • 29. cas concret #1 : site Symfony > Bien sûr, la classe eZConfiguration ne fonctionnera pas > Il nous faut une classe YamlConfiguration Réutilisabilité du code Page 29
  • 30. cas concret #1 : site Symfony class YamlConfiguration implements Configuration { public function read($variableName, $defaultValue) { list($file, $group, $variable) = explode(self::SEPARATOR, $variableName); $loader = Yaml::parse($file); if(array_key_exists($loader[$group][$variable])) { return $loader[$group][$variable]; } return $defaultValue; } } Réutilisabilité du code Page 30
  • 31. cas concret #1 : site Symfony > Construction du serveur : $configuration = new YamlConfiguration(); $server = new TagServer($configuration); > Et …. c’est tout ! Réutilisabilité du code Page 31
  • 32. 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 > 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 Réutilisabilité du code Page 32
  • 33. Cas concret #2 Réutilisabilité du code
  • 34. 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é Réutilisabilité du code Page 34
  • 35. cas concret #2 class TagServer { private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } } Réutilisabilité du code Page 35
  • 36. cas concret #2 : empilement de paramètres class TagServer { private $rules, $logger; public function __construct(Configuration $configuration, Logger $logger) { $this->logger = $logger; $this->rules = $configuration->read( 'tagserver/Tags/Rules', array() ); } } Réutilisabilité du code Page 36
  • 37. 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 Injection par mutateur Réutilisabilité du code Page 37
  • 38. cas concret #2 : injection par mutateur class TagServer { private $logger; public function __construct(Configuration $configuration) { $this->logger = null; /* ... */ } public function setLogger(Logger $logger) { $this->logger = $logger; return $this; } } Réutilisabilité du code Page 38
  • 39. cas concret #2 : injection par mutateur private function writeLog($message) { if($this->logger !== null) { $this->logger->write($message); } } > Et l’appel : $server = new TagServer(new eZConfiguration()); $server->setLogger(new eZLogger()); Réutilisabilité du code Page 39
  • 40. 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 nombreuses classes. Réutilisabilité du code Page 40
  • 41. cas concret #2 : conteneur d’injection > Solution : recours à un conteneur d’injection > Pimple (Sensio Labs) > DI Component de Symfony (Sensio Labs) > Objet en charge de l’instanciation des autres objets Réutilisabilité du code Page 41
  • 42. cas concret #2 : conteneur commun abstract class Container extends Pimple { public function __construct() { $this['tagServer'] = function ($container){ $server = new TagServer($container['configuration']); $server->setLogger($container['logger']); return $server; }; } } Réutilisabilité du code Page 42
  • 43. cas concret #2 : conteneur d’injection Conteneur commun à tous les socles techniques Conteneurs spécifiques Réutilisabilité du code Page 43
  • 44. cas concret #2 : conteneur spécifique (eZ Publish) class eZContainer extends Container { public function __construct() { parent::__construct(); $this['configuration'] = function ($container){ return new eZConfiguration(); }; $this['logger'] = $this->share(function ($container){ return new eZLogger(); }); } } Réutilisabilité du code Page 44
  • 45. cas concret #2 : conteneur d’injection > Et la construction de notre classe : $container = new eZContainer(); $server = $container['tagServer']; Réutilisabilité du code Page 45
  • 46. 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 - Dépendances masquées : quid des outils d’analyse ? Réutilisabilité du code Page 46
  • 47. Et si on testait ? Réutilisabilité du code
  • 48. testabilité : souvenez-vous class TagServer { private $rules; public function __construct() { $this->rules = array(); $ini = eZINI::instance('tagserver.ini'); $ini->assign('Tags', 'Rules', $this->rules); } // ... } Réutilisabilité du code Page 48
  • 49. 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 > Et si eZINI était un service à bouchonner ? (comme la db, un webservice ou le filesystem) Réutilisabilité du code Page 49
  • 50. testabilité : ArrayConfiguration > Il faut mocker la configuration ArrayConfiguration ! Réutilisabilité du code Page 50
  • 51. testabilité : ArrayConfiguration class ArrayConfiguration implements Configuration { private $values; public function __construct(array $values) { $this->values = $values; } public function read($variableName, $defaultValue) { if(array_key_exists($variableName, $this->values)) { return $this->values[$variableName]; } return $defaultValue; } } Réutilisabilité du code Page 51
  • 52. testabilité : le test unitaire class TagServerTest extends PHPUnit_Framework_TestCase { private $tagServer; public function setUp() { $configuration = new ArrayConfiguration(array( 'tagserver/Tags/Rules' => array(/* ... */) )); $this->tagServer = new TagServer($configuration); } } Réutilisabilité du code Page 52
  • 53. testabilité : bilan > C’est testable ! > C’est performant ! > Le test est facile à maintenir ! > Possibilité de tester aussi les cas à la marge : - Configuration manquante - Configuration erronée - Configuration non consistante - … Réutilisabilité du code Page 53
  • 55. si vous avez des questions ? Nicolas Le Nardou Architecte / Expert Technique PHP nicolas.lenardou@orange.com Réutilisabilité du code Page 55