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

C0040b96f9fb1adf5e8b99056b570c8a?s=128

GBProd

May 12, 2016
Tweet

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 ?