Slide 1

Slide 1 text

Symfony2 : un framework orienté DDD ? Jean-François Lépine – Novembre 2013

Slide 2

Slide 2 text

En face de vous ● Jean-François Lépine ● Consultant PHP chez Alter Way ● @Halleck45 ● http://blog.lepine.pro

Slide 3

Slide 3 text

Ce qu'on va aborder ● Rappel rapide de ce qu'est Symfony2 ● Rappel un peu moins rapide de ce que c'est que le DDD ● Symfony2 et Doctrine2 sont-ils orientés DDD ? ● Retours d'expériences de deux projets DDD avec Symfony2

Slide 4

Slide 4 text

Piqûre de rappel

Slide 5

Slide 5 text

Symfony 2 ● Communauté très active ● Open Source ● Support – Gratuit (6 mois, ou 2 ans pour les LTS) – Payant (3 ans) ● Framework – Full stack – Composants

Slide 6

Slide 6 text

Des outils ● BrowserKit ● ClassLoader ● Config ● Console ● CssSelector ● Debug ● DependencyInjection ● DomCrawler ● EventDispatcher ● Filesystem ● Finder ● Form ● HttpFoundation ● HttpKernel ● Locale ● Intl ● Icu ● OptionsResolver ● Process ● PropertyAccess ● Routing ● Security ● Serializer ● Stopwatch ● Templating ● Translation ● Validator ● Yaml

Slide 7

Slide 7 text

Une philosophie ● Orienté Requête / Réponse ● Ne pas réinventer la roue : ● Twig ● PHPUnit ● KISS (ou presque) ● Tout est « Bundle » ● KnpBundles.com : 2 000 bundles !

Slide 8

Slide 8 text

Un cadre de travail ● Conventions de code ● Bonnes pratiques (injection de dépendances, etc. ) ● PSR (nommage, logs, etc.) ● Cadre « devops » ● Déploiement (capistrano / capifony) ● Cache HTTP, tags ESI...

Slide 9

Slide 9 text

Domain Driven design

Slide 10

Slide 10 text

Une démarche de travail ● Le code source est le reflet du besoin fonctionnel ● Le code source adopte le vocabulaire fonctionnel ● Le code source facilite : – Le changement – La gestion des règles métiers – La maintenabilité

Slide 11

Slide 11 text

Une langue commune ● Eviter les ambiguïtés ● Est élaborée en commun ● Est parlée par tous ● Glossaire du projet UBIQUITOUS LANGAGE

Slide 12

Slide 12 text

Entité ● Est unique ● Est identifiable ● Son identité est immutable

Slide 13

Slide 13 text

Aggrégat ● Représente une ≈Collection d'entités ● Se manipule comme s'il s'agissait d'une seule Entité

Slide 14

Slide 14 text

Repository ● Permet de retrouver et de persister les entités

Slide 15

Slide 15 text

Service et Spécification Service ● Exerce les Comportements métiers ● Est un service purement fonctionnel (pas de classe outils) Spécification ● Représente une règle métier $dog=new Dog; $rule=new CanBeSoldSpecification; if($rule­>isSatisfedBy($dog)) { // ... }

Slide 16

Slide 16 text

Objet valeur ● Représente une Information ● Est immutable ● Un identifiant ● Une Date ● Un Montant ● Une Adresse ● ...

Slide 17

Slide 17 text

Isolation

Slide 18

Slide 18 text

Spécialisation

Slide 19

Slide 19 text

Testabilité

Slide 20

Slide 20 text

Testabilité

Slide 21

Slide 21 text

Keep It Simple and Stupid ! ● Un objet simple par règle métier ● La complexité se fait par l'assemblage de composants simples et réutilisables

Slide 22

Slide 22 text

Doctrine 2 et DDD

Slide 23

Slide 23 text

Au fait... ● « DDD is not about framework or tools... »

Slide 24

Slide 24 text

Doctrine 2 et DDD

Slide 25

Slide 25 text

Doctrine 2 ● Doctrine 2 contient en partie le vocabulaire du DDD ● Entities ● Repositories ● ObjectValue (DbalTypes) ● Aggregates (Collection) ● S'agit-il des mêmes concepts que le DDD ?

Slide 26

Slide 26 text

Doctrine 2, outil du DDD ? Oui ● Entité ● Repository Peut-être ● Aggrégat ● Identifiants Non ● Object Value

Slide 27

Slide 27 text

Doctrine 2 et Objet valeur ● En théorie, les DbalTypes sont des Objets Valeur ● En pratique, les Objets Valeurs sont des entités spécifiques ● Doctrine 2 gère difficilement les Types complexes (ex : une adresse, elle même composée de rue, ville, etc.) ● Doctrine 2 permet difficilement de serializer des DbalTypes autrement qu'en String

Slide 28

Slide 28 text

Doctrine 2 et Aggrégat ● En théorie, il est possible de déterminer comment une Collection sera persistée ● En théorie, il est possible d'utiliser des Collections personnalisées à la place des Collection Doctrine ● En pratique, pour être viable, il faut un peu d'investissement

Slide 29

Slide 29 text

Doctrine 2 et Identifiants ● Doctrine2 ne pousse pas assez à l'utilisation de vrais identifiants : ● La systématisation de l'utilisation de vrais Identifiants ne fait pas partie de Doctrine2 class UserRepository { public function getById(UserId $id) { } }

Slide 30

Slide 30 text

Symfony2 et DDD

Slide 31

Slide 31 text

Symfony2, outil du DDD ? Oui ● Atomisation des comportements ● Anonymisation du framework Peut-être ● Couplage et Cohésion Non ● Validation des données ● Service ≠ Service ● Architecture de base

Slide 32

Slide 32 text

Oui : atomisation, anonymisation ● Atomisation ● Les framework pousse au respect des principes SOLID ● Anonymisation ● L'injection de dépendances + utilisation d'alias permet d'écrire du code « sans framework » services: domain.acl.provider: alias: acl_provider services: mon.domain.service: arguments: ­ domain.acl.provider

Slide 33

Slide 33 text

Peut-être : cohésion et couplage ● En théorie, il est possible d'écrire du code totalement indépendant du framework ● En réalité, le code est écrit dans un cadre (framework) ● En réalité, ce n'est pas grave pour les couches Application et Infrastructure

Slide 34

Slide 34 text

Non : validation de données ● Validation dans Symfony2 = JSR 303 (Bean Validation) 1. Les objets contiennent des règles de validation 2. Les objets sont remplis avec les données à valider (potentiellement invalides) 3. Les objets sont validés ● Une entité doit toujours être dans un état valide ● Le processus classique de validation de données dans Symfony2 introduit une complexité forte dans la logique DDD

Slide 35

Slide 35 text

Non : service ● Service Symfony2 ≠ Service DDD ● La confusion due au vocabulaire est très difficile à surmonter, même pour des développeurs confirmés

Slide 36

Slide 36 text

Non : architecture ● Plus grosse difficulté pour le DDD ● Où placer mes entités ? ● Comment séparer mes couches ? Dans un seul bundle ? Dans plusieurs bundles ? ● Mon domain est-il un Bundle comme un autre ?

Slide 37

Slide 37 text

du DDD avec Symfony2 Retour d'expériences

Slide 38

Slide 38 text

A la recherche du Graal ● Pas mal de tentatives différentes ● Pas de solution miracle jusqu'ici

Slide 39

Slide 39 text

Projet 1 ● Gros projet Alter Way, > 1000 jours / homme ● 5 dépôts GIT ● UserInterface : BackboneJS ● Application : Contrôleurs Symfony2, ApiResource, Forms ● Model : Entités et Déclaration d'entités Doctrine2 ● Domain : Services et Spécifications métier Symfony2 ● Infrastructure : outils ● Tout est Bundle

Slide 40

Slide 40 text

Projet 1 : refractoring ● Au bout de 6 mois, refractoring important ● 2 dépôts Git : ● Front-end BackboneJS ● Back-end Symfony2

Slide 41

Slide 41 text

Au bout d'un an ● Ambiguïté sur la notion de « Bundle » ● Couplage assez fort entre le Domain et Symfony2 ● Globalement viable et de bonne qualité

Slide 42

Slide 42 text

Projet 2 ● 2 dépôts Git : ● Front-end AngularJs ● Back-end Symfony2, PHP ● Des bundles ● UiApi et UiCli ● Sécurité ● Liaison DDD / Sources ● Une librairie DDD (contrats) ● Des sources métier

Slide 43

Slide 43 text

Symfony2++ ● Contexte fonctionnel dans Symfony2 : ● Introduction de la notion d' « Acteur » (ou Agent) ● Renforcement de l'utilisation d'Evénements public function activateProjectAction(Project $project, Context $context) { } public function editAction(Project $project, EditableContext $context) { }

Slide 44

Slide 44 text

Symfony2++ ● Plus de DQL, mais des décorateurs de Critères : /** * @Criteria(for="users", criteria="Acme\...\Criteria\UsersOfProject", service="acme.projects.service ) */ public function userstAction(Project $user, UserCollection $users) { } class UsersOfProject extends Criteria { public function apply($queryBuilder) { $project = $this­>bag­>getProject(); $queryBuilder­>field('projects.$id')­>equals($project­>getId()); } }

Slide 45

Slide 45 text

Difficultés ● Il a fallu tout externaliser ● Par exemple : ● Il faut parfois se battre avec la logique Symfony2 / Doctrine ● Ex : ACL peu évolutifs doctrine_mongodb: connections: mappings: model: type: yml dir: %kernel.root_dir%/../../src/Acme/Application/Mapping prefix: Hal\Manage\Crm\Domain alias: Acme\Domain is_bundle: false

Slide 46

Slide 46 text

Difficultés ● Nécessite des compétences avancées ● Et en Symfony2 ● Et en POO

Slide 47

Slide 47 text

Au bout d'un an (ou presque) ● Couplage très faible entre le framework et Symfony 2 ● Couche Domain très « propre » ● Une grande question :

Slide 48

Slide 48 text

Une grande question ● « Mais pourquoi utiliser Symfony2 framework plutôt que Component ou Silex !?! » ● Confusion entre Framework et outils ● « Projet 3 » en cours ● 1 dépôt UI : AngularJs ● 1 dépôt Application : Symfony2 Framework ● 1 dépôt Domain : PHP ● 1 dépôt Infrastructure : Symfony2 Component

Slide 49

Slide 49 text

Conclusion

Slide 50

Slide 50 text

Symfony2 et DDD ● Symfony2 n'est pas vraiment orienté DDD ● Symfony2 + Doctrine2 se prête assez bien au DDD ● Mais ce ne sont PAS des recettes miracle ● Peuvent être des freins ● Doivent être détournés ● Nécessitent un bon niveau technique

Slide 51

Slide 51 text

Merci ! ● C'est l'heure des questions ● Et de la pub:-) ● http://communiquez.lepine.pro : eBook open source sur le Bevahior Driven Development)