Pourquoi le DDD ne devrait rien changer à votre vie

Pourquoi le DDD ne devrait rien changer à votre vie

12fad6dce4099a21ed70cf4409fe2271?s=128

Alexandre Balmes

January 30, 2016
Tweet

Transcript

  1. POURQUOI LE DDD
 NE DEVRAIT RIEN CHANGER A VOTRE VIE

  2. ABOUT ME ➤ Alexandre Balmes ➤ Independant Software Consultant ➤

    Co-fondateur de Vanoix ➤ J’aime le PHP et il me le rends bien ➤ Twitter : @pockystar
  3. AU COMMENCEMENT

  4. “ C’est pas grave, je ferais l’introduction -Alexandre Balmes

  5. J’AI UN PROBLEME

  6. J’AI UN PROBLEME
 JE DOIS VOUS PARLER DE DDD

  7. J’AI UN PROBLEME JE DOIS VOUS PARLER DE DDD EN

    PHP
  8. <?php
 
 namespace AppBundle\Entity;
 use Doctrine\ORM\Mapping as ORM; 
 /**


    * Class Stuff
 *
 * @ORM\Entity()
 */
 class Stuff
 {
 /**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
 protected $id;
 
 /**
 * @ORM\Column(type="string", length=255)
 */
 protected $title;
 
 public function getId()
 {
 return $this->id;
 }
 
 public function setTitle($title)
 {
 $this->title = $title;
 }
 
 public function getTitle()
 {
 return $this->title;
 }
 }

  9. VERSUS

  10. <?php
 
 namespace AppBundle\Entity;
 
 use App\Domain\Entity\Stuff as BaseStuff;
 


    /**
 * Class Stuff
 */
 class Stuff extends BaseStuff
 {
 protected $id;
 
 public function getId() : int
 {
 return $this->id;
 }
 }
 <?php
 
 namespace App\Domain\Entity;
 use App\Domain\ValueObject\StuffId; 
 /**
 * Class Stuff */
 class Stuff
 {
 protected $stuffId;
 
 protected $title;
 
 private function __construct();
 
 public static function buildStuffFromFoobar(StuffId $id, string $title)
 {
 $this->stuffId = $id;
 $this->title = $title;
 } public function getStuff() : array
 {
 return [
 "id" => $this->stuffId,
 "title" => $this->title,
 ];
 } }
 
 AppBundle\Entity: type: entity id:
 id:
 type: integer
 generator: { strategy: AUTO } App\Domain\Entity\Stuff:
 type: mappedSuperclass
 fields:
 title: { type: string }
 embedded:
 stuffId:
 class: App\Domain\ValueObject\StuffId
  11. None
  12. DOMAIN-DRIVEN DESIGN

  13. HISTORIQUE ➤ Un homme : Eric Evans ➤ Un livre

    : Domain-Driven Design: Tackling Complexity in the Heart of Software (2003 - Addison Wesley) ➤ Une idéologie : DDD => Software Craftsmanship => XP => TDD
  14. “Leading software designers have recognized domain modeling and design as

    critical topics for at least 20 years, yet surprisingly little has been written about what needs to be done or how to do it. Although it has never been formulated clearly, a philosophy has emerged as an undercurrent in the object community, a philosophy I call domain-driven design. -Eric Evans
  15. OBJECTIFS ➤ Comprendre le métier du client ➤ Modéliser le

    métier ➤ Retranscrire le vocabulaire
  16. POURQUOI ? ➤ Le coeur d’une application c’est son métier

    (= son Domain) ➤ L’interface graphique, les services tiers peuvent régulièrement changer mais le métier beaucoup moins ➤ Le métier peut évoluer, stagner, disparaitre mais il ne devrait pas être “réinitialisé”
  17. CONSEQUENCES ➤ Le DDD est une boite à outil :

    ➤ SOLID ➤ regroupant des bonnes pratiques de conception ➤ permettant la communication entre porteur de projet et développeurs à travers un language commun
  18. PLUTÔT NORMAL NON ?

  19. <?php
 namespace AppBundle\Entity;
 use Doctrine\ORM\Mapping as ORM; /**
 * Class

    Stuff
 *
 * @ORM\Entity()
 */
 class Stuff
 {
 /**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
 protected $id;
 /**
 * @ORM\Column(type="string", length=255)
 */
 protected $title;
 public function getId()
 {
 return $this->id;
 }
 public function setTitle($title)
 {
 $this->title = $title;
 }
 public function getTitle()
 {
 return $this->title;
 }
 }
 ALORS POURQUOI ?
  20. None
  21. QUESTIONS !

  22. EST-IL ACCEPTABLE 
 POUR VOUS DE :

  23. PASSER DES HEURES A ESSAYER DE DECRYPTER DU CODE ?

  24. DE NE PAS POUVOIR DEVELOPER CERTAINES FONCTIONNALITÉS SOUS PRETEXTE DE

    ?
  25. D’ETRE BLOQUÉ PAR LA TECHNO ?

  26. DES IDÉES SIMPLES Qui changent un peu la vie

  27. UBIQUITOUS LANGUAGE ➤ “N’importe quel utilisateur” doit pouvoir comprendre le

    code ➤ Le code doit refléter le language du métier, son vocabulaire, ses termes… ➤ Il faut chercher les experts métiers et les confronter au code ➤ Le business comprend le dévelopeur, le dévelopeur comprends le business
  28. LAYERED ARCHITECTURE User Interface Application Domain Infrastructure Form Specification Service

    Entity
 ValueObject Enum
 DomainEvents Bridge
 CQRS
 Listener
 Persistence DTO
 Serializer … Service
 Repository … Services
 Mailer
 … Controller Action Responder
  29. BOUNDED CONTEXT ➤ Une information n’a pas de sens sans

    contexte, ➤ Il est important de décomplexifier une application en la segmentant suivant ses contextes ➤ Une “Context map” permet de savoir qui travaille avec qui et de quelle manière (les collaborateurs) ➤ ProTip : Un channel monolog par contexte (plus d’info : http://www.slideshare.net/ javier.eguiluz/new-symfony-tips-tricks-symfonycon-paris-2015)
  30. ITERATIVE DEVELOPMENT ➤ De l’agile tout simplement ➤ Chaque modification

    du language peut provoquer : ➤ Une modification du Domain ➤ L’ajout d’un contexte ➤ Du code d’Infrastructure ou d’Application en plus ou en moins ➤ …
  31. C’EST CA LE DOMAIN-DRIVEN DESIGN

  32. MISE EN PRATIQUE Des patterns que l’on devrait tous utiliser

  33. “ Moi quand je veux écrire une page, je met

    d’abord son titre et sa description puis je remplis son contenu. - Jane Doe
  34. “ Moi quand je veux écrire une page, je met

    d’abord son titre et sa description puis je remplis son contenu. - Jane Doe Auteur Action Constructeur Propriétés
  35. Page __construct(Author $author, string $title, string $description) writeContent(string $content) Author

    __construct(string $author) getValue() : string isSatisfiedBy() : boolean CreatePageAction::__invoke(ServerRequestInterface $request) UserInterface Domain
  36. Page __construct(Author $author, string $title, string $description) writeContent(string $content) Author

    __construct(string $author) getValue() : string isSatisfiedBy() : boolean CreatePageAction::__invoke(ServerRequestInterface $request) UserInterface Domain PageService::create(string $author, string, $title, $string description) Infrastructure
  37. Page __construct(AuthorId $uid, Author $author, string $title, string $description) writeContent(string

    $content) CreatePageAction::__invoke(ServerRequestInterface $request) UserInterface Domain PageService::create(string $author, string, $title, $string description) Infrastructure PageRepository::__construct(Page::class) getClassName() : string save() Author + AuthorId __construct(string $author) getValue() : string isSatisfiedBy() : boolean NewPageHasBeenCreatedEv ent::__construct(Page $page)
  38. CreatePageAction::__invoke(ServerRequestInterface $request) UserInterface Domain PageService::create(CreatePageDTO $dto) Infrastructure CreatePageDTO::__construct(string $author, string

    $title, string $description) Page __construct(AuthorId $uid, Author $author, string $title, string $description) writeContent(string $content) PageRepository::__construct(Page::class) getClassName() : string save() Author + AuthorId __construct(string $author) getValue() : string isSatisfiedBy() : boolean NewPageHasBeenCreatedEv ent::__construct(Page $page) Application
  39. Application + UI Domain Infrastructure CreatePageCommand::__construct(Author $author, string $title, string

    $description) CreatePageHandler::handle(CreatePageCommand $command) PageService::create(CreatePageDTO $dto) PageWriteRepository::__construct(Page::class) getClassName() : string Page __construct(AuthorId $uid, Author $author, string $title, string $description) writeContent(string $content) Author + AuthorId __construct(string $author) getValue() : string isSatisfiedBy() : boolean NewPageHasBeenCreatedEv ent::__construct(Page $page)
  40. “ Pour lire une page, il faut qu’elle soit publiée

    - Jane Doe
  41. “ Pour lire une page il faut qu’elle soit publiée

    - Jane Doe Action Propriété Méthode
  42. Page __construct(Author $author, string $title, string $description) writeContent(string $content) publish()

    read() : array Author __construct(string $author) getValue() : string isSatisfiedBy() : boolean ReadPage::__invoke(ServerRequestInterface $request) UserInterface Domain
  43. Page __construct(Author $author, string $title, string $description) writeContent(string $content) publish()

    read() : array Author __construct(string $author) getValue() : string isSatisfiedBy() : boolean ReadPage::__invoke(ServerRequestInterface $request) UserInterface Domain PageService::read(PageId $id) : Page Infrastructure PageRepository::__construct(Page::class) getClassName() : string findById(PageId $id) : Page
  44. ReadPage::__invoke(ServerRequestInterface $request) UserInterface Domain PageService::read(PageId $id) : Page Infrastructure PageORMRepository::__construct(ObjectManager

    $manager, Page::class) getClassName() : string findById(PageId $id) : Page PageIsReadableSpecification::isSatisfiedBy(Page $page) : boolean Application
  45. ET MON BUNDLE/PLUGIN/MODULE ?

  46. HEXAGONAL Infrastructure Application DOMAIN Adapter
 /Bridge Adapter
 /Bridge Adapter
 /Bridge

    Adapter
 /Bridge Adapter
 /Bridge Adapter
 /Bridge Persistence Mailer Listener CQRS API Client Bundle
 Plugin
 Module
  47. ET MON SYMFONY ? ➤ Adoptez PSR-4 ! {
 "name":

    "black-project/black-standard-edition",
 "license": "MIT",
 "type": "project",
 "description": "The \"Black Edition\" distribution build on top of \"Symfony Standard Edition\"",
 "autoload": {
 "psr-4": {
 "Black\\Website\\": "src/Website/",
 "Black\\Bundle\\WebsiteBundle\\": "src/Website/Infrastructure/Bridge/Symfony/ WebsiteBundle/"
 },
 "classmap": [ "app/AppKernel.php", "app/AppCache.php" ]
 }, // Stuff }
  48. MON DDD Le mien à moi que j’aime

  49. SYMFONY-LESS

  50. SYMFONY-LESS ➤ Mais utilisant des composants Symfony ➤ Mais pouvant

    être facilement encapsulé dans Symfony ou autre chose (via les Bridge) ➤ Mais surtout pouvant être utilisé dans un Middleware ➤ Puli : Universal Packages for PHP (Resource access et discovery)
  51. SYMFONY-LESS ➤ Directory structure : ➤ src/Application/<Context>/[…] ➤ src/Domain/<Context>/[…] ➤

    src/Infrastructure/<Context>/[…] ➤ res/config ➤ res/views
  52. PHP7 FOR THE WIN

  53. PHP7 FOR THE WIN ➤ PHP7 est version majeure ➤

    Improved performance: PHP 7 is up to twice as fast as PHP 5.6 ➤ Significantly reduced memory usage ➤ Abstract Syntax Tree ➤ Many fatal errors converted to Exceptions ➤ Secure random number generator ➤ The null coalescing operator (??) ➤ Return and Scalar Type Declarations ➤ Anonymous Classes
  54. PHP7 FOR THE WIN ➤ PHP7 est version majeure ➤

    Improved performance: PHP 7 is up to twice as fast as PHP 5.6 ➤ Significantly reduced memory usage ➤ Abstract Syntax Tree ➤ Many fatal errors converted to Exceptions ➤ Secure random number generator ➤ The null coalescing operator (??) ➤ Return and Scalar Type Declarations ➤ Anonymous Classes
  55. PSR-7 FOR THE WIN

  56. PSR-7 FOR THE WIN ➤ Standardisation des échanges : ➤

    La requête : ServerRequestInterface ➤ La réponse : ResponseInterface ➤ Une URI : UriInterface ➤ Un fichier uploadé : UploadedInterface
 ➤ Utilisé dans notamment : ➤ Slim3 ➤ Zend3 : Stratigility/Diactoros/Expressive ➤ Symfony via symfony/psr-http-message-bridge
  57. ACTION - DOMAIN - RESPONDER

  58. ACTION - DOMAIN - RESPONDER ➤ J’ai dit bye bye

    au MVC : ➤ Un contrôleur -> X actions avec toutes les dépendances = mauvaise idée ➤ Un contrôleur -> 1 action avec ses propres dépendances = meilleure idée
  59. ACTION - DOMAIN - RESPONDER ➤ J’ai dit bonjour à

    l’ADR : ➤ Déjà le naming est “parlant” ➤ Une Action de type Callable dont l’objectif est de traiter une requête et d’interagir avec le Domain ➤ Un Responder de type Callable dont l’objectif est de présenter les données provenants de l’Action ➤ C’est possible avec Symfony depuis la version 2.6
  60. BDD/SPECBDD DOMAIN MODELING

  61. None
  62. CONCLUSION Si je devais résumer

  63. J’AIME LE DDD

  64. PARCE QU’IL DONNE DU SENS 
 A MON TRAVAIL SUR

    LE LONG TERME
  65. PARCE QU’IL CADRE
 MON CODE
 SUR LE LONG TERME

  66. PARCE QUE MES CLIENTS
 APPRECIENT DE PARTAGER

  67. DES MOMENTS JE NE 
 FAIS PAS DE DDD

  68. J’UTILISE LES BONNES IDEES DU DDD DANS UN CONTEXTE PRECIS

  69. J’UTILISE DES DESIGN PATTERNS MIS EN AVANT DANS LE DDD

  70. ET CA FONCTIONNE TRÈS BIEN

  71. J’AIME SYMFONY/SYMFONY

  72. C’EST GRACE A LUI (EUX) QUE JE SUIS DEVANT VOUS

  73. MAIS JE NE PEUX PAS
 MISER MA CARIERE SUR SYMFONY

  74. PARCE QUE LE METIER DETERMINE LES OUTILS PAS L’INVERSE

  75. MERCI