Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DDD: Retour d'expérience

DDD: Retour d'expérience

Retour d'expérience sur ce que j'ai appris lors d'un projet perso fait en Symfony et en Domain

GBProd

May 12, 2016
Tweet

More Decks by GBProd

Other Decks in Technology

Transcript

  1. DDD: Retour d’expérience @GillesRoustan

  2. Ma façon d’apprendre

  3. I can’t decide

  4. Pourquoi DDD ?

  5. /** * @ORM\Table(name="oc_advert") * @ORM\Entity(repositoryClass="OC\PlatformBundle\Repository\AdvertRepository") * @ORM\HasLifecycleCallbacks() */ class Advert

    { /** * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\Column(name="date", type="datetime") * @Assert\DateTime() */ private $date; /** * @ORM\Column(name="author", type="string", length=255) * @Assert\Length(min=2) */ private $author; /** * @ORM\Column(name="content", type="text") * @Assert\NotBlank() */ private $content; /** * @ORM\OneToOne(targetEntity="OC\PlatformBundle\Entity\Image", cascade={"persist", "remove"}) * @Assert\Valid() */ Code first
  6. None
  7. DDD to the rescue

  8. 4 couches

  9. Core Domain Aggregats, Entités, Object Value...

  10. Application

  11. Presentation

  12. Infrastructure Persistance, framework

  13. Core Domain

  14. Aggregat

  15. Aggregat Question Question - text - endDate Identifier Author Options

  16. Racine de l’aggregat

  17. Entité

  18. Objets valeurs

  19. Apporter du sens

  20. Utiliser langage commun dans le modèle • Utiliser des constructeurs

    nommés • Tous les paramètres obligatoires sont dans le constructeur • Utiliser des méthodes plutôt que des setters • Rendre les classes du domaines finales • Utiliser des factories
  21. QuestionRepository final class Question { public static function ask( QuestionIdentifier

    $id, Author $author, $text, array $options, \DateTimeImmutable $endDate ) { } private function __construct(...) { }
  22. Identifier les entités

  23. UUID ramsey/uuid

  24. Avec doctrine ? • Utilisez le type embeddable pour les

    Object Value • Utilisez le YAML/XML au lieu des annotations (dans la couche infrastructure) • Attention aux jointures • Les id en Object Value, c’est possible
  25. Repository

  26. QuestionRepository <?php namespace GBProd\ICantDecide\CoreDomain\Question; interface QuestionRepository { public function find(QuestionIdentifier

    $id); public function save(Question $question); }
  27. Spécifications

  28. QuestionRepository <?php namespace GBProd\ICantDecide\CoreDomain\Question; interface QuestionRepository { public function findSatisfying(Specification

    $spec); }
  29. Une spécification <?php namespace GBProd\ICantDecide\CoreDomain\Specification\Question; use GBProd\Specification\CompositeSpecification; class IsAvailable extends

    CompositeSpecification { public function isSatisfiedBy($candidate) { return $candidate->getEndDate() > new \DateTime('now'); } }
  30. Une spécification avec paramètres <?php namespace GBProd\ICantDecide\CoreDomain\Specification\Question; use GBProd\Specification\CompositeSpecification; class

    HasMoreVoteThan extends CompositeSpecification { public function __construct($minVote) { $this->minVotes = $minVotes; } public function isSatisfiedBy($candidate) { [...]
  31. Composition <?php $manyVotes = new HasMoreVoteThan(1000); $available = new IsAvailable();

    $byMe = new IsAskedBy(‘gbprod’); $isPopular = $available ->andX($manyVotes) ->andX($byMe->not()) ; $isPopular>isSatifiedBy($question);
  32. Avec symfony ? kphoen/rulerz happyr/doctrine-specification

  33. Next ?