groupe de presse > 20-30 sites en PHP - eZ Publish, Symfony 2, WordPress, from scratch, … > Forte audience : environ 10M de pages vues / jour Page 2 Ré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
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 3 Réutilisabilité du code
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 4 Réutilisabilité du code > Objectifs : - Mutualiser la maintenance du code - Réduire les temps de développement
> « 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 9 Ré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
être fermée à la modification et ouverte à l’extension » > Une évolution ne devrait pas vous faire casser du code, juste en ajouter ! Page 10 Réutilisabilité du code > Une classe doit prévoir de pouvoir être étendue sans être réécrite.
à 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 11 Réutilisabilité du code
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 12 Réutilisabilité du code
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 13 Réutilisabilité du code > Pas d’utilisation du mot clé new dans une classe > Injection par constructeur ou mutateur
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 15 Réutilisabilité du code - 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
2 développements distincts - Dupliquer la classe et la modifier Page 16 Réutilisabilité du code - Nombreux paramètres dans le constructeur - Ou toute autre abomination …
= array(); $ini = eZINI::instance('tagserver.ini'); $ini->assign('Tags', 'Rules', $this->rules); Page 18 Réutilisabilité du code > Couplage fort : TagServer dépend de eZINI La classe n’est réutilisable que sur un autre site eZ Publish }
eZINI dans le constructeur > On pourra ainsi substituer à une occurrence d’eZINI, un objet d’une Injection de dépendances (SOLID) Page 19 Réutilisabilité du code > On pourra ainsi substituer à une occurrence d’eZINI, un objet d’une sous classe d’eZINI
> 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 22 Réutilisabilité du code Il nous faut une interface « Configuration » Séparation d’interfaces (SOLID)
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 25 Réutilisabilité du code
eZConfiguration(); $server = new TagServer($configuration); > Fonctionne à nouveau pour eZ Publish Page 27 Réutilisabilité du code > Fonctionne à nouveau pour eZ Publish - Sans modification de la classe TagServer Open / Closed (SOLID)
: > Et …. c’est tout ! $configuration = new YamlConfiguration(); $server = new TagServer($configuration); Page 31 Réutilisabilité du code > Et …. c’est tout !
notre classe TagServer sur un autre framework PHP ≈ Coût de développement d’une classe d’adaptation pour accéder à la configuration Page 32 Ré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
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 34 Réutilisabilité du code
configuration, le logger est une dépendance faible > Un logger n’est pas requis pour le fonctionnement de notre classe Page 37 Réutilisabilité du code Injection par mutateur
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 40 Réutilisabilité du code > Par exemple, il a fort à parier que le logger soit nécessaire sur de nombreuses classes.
à un conteneur d’injection > Pimple (Sensio Labs) > DI Component de Symfony (Sensio Labs) Page 41 Réutilisabilité du code > Objet en charge de l’instanciation des autres objets
Pimple { public function __construct() { $this['tagServer'] = function ($container){ $server = new TagServer($container['configuration']); Page 42 Réutilisabilité du code $server->setLogger($container['logger']); return $server; }; } }
extends Container { public function __construct() { parent::__construct(); $this['configuration'] = function ($container){ return new eZConfiguration(); Page 44 Réutilisabilité du code return new eZConfiguration(); }; $this['logger'] = $this->share(function ($container){ return new eZLogger(); }); } }
- Le conteneur peut s’appuyer sur de la configuration (ex: Symfony) - Risque de dépendance au conteneur + global state Page 46 Réutilisabilité du code - Dépendances masquées : quid des outils d’analyse ?
Problème de performances des tests > Un fichier eZINI est également nécessaire Eparpillement du code de test Maintenabilité affaiblie Page 49 Réutilisabilité du code > Et si eZINI était un service à bouchonner ? (comme la db, un webservice ou le filesystem)
! > Le test est facile à maintenir ! Page 53 Réutilisabilité du code > Possibilité de tester aussi les cas à la marge : - Configuration manquante - Configuration erronée - Configuration non consistante - …