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

    View Slide

  2. Ma façon d’apprendre

    View Slide

  3. I can’t decide

    View Slide

  4. Pourquoi DDD ?

    View Slide

  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

    View Slide

  6. View Slide

  7. DDD to the rescue

    View Slide

  8. 4 couches

    View Slide

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

    View Slide

  10. Application

    View Slide

  11. Presentation

    View Slide

  12. Infrastructure
    Persistance, framework

    View Slide

  13. Core Domain

    View Slide

  14. Aggregat

    View Slide

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

    View Slide

  16. Racine
    de l’aggregat

    View Slide

  17. Entité

    View Slide

  18. Objets valeurs

    View Slide

  19. Apporter du sens

    View Slide

  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

    View Slide

  21. QuestionRepository
    final class Question
    {
    public static function ask(
    QuestionIdentifier $id,
    Author $author,
    $text,
    array $options,
    \DateTimeImmutable $endDate
    ) {
    }
    private function __construct(...)
    {
    }

    View Slide

  22. Identifier les entités

    View Slide

  23. UUID
    ramsey/uuid

    View Slide

  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

    View Slide

  25. Repository

    View Slide

  26. QuestionRepository
    namespace GBProd\ICantDecide\CoreDomain\Question;
    interface QuestionRepository
    {
    public function find(QuestionIdentifier $id);
    public function save(Question $question);
    }

    View Slide

  27. Spécifications

    View Slide

  28. QuestionRepository
    namespace GBProd\ICantDecide\CoreDomain\Question;
    interface QuestionRepository
    {
    public function findSatisfying(Specification $spec);
    }

    View Slide

  29. Une spécification
    namespace GBProd\ICantDecide\CoreDomain\Specification\Question;
    use GBProd\Specification\CompositeSpecification;
    class IsAvailable extends CompositeSpecification
    {
    public function isSatisfiedBy($candidate)
    {
    return $candidate->getEndDate() > new \DateTime('now');
    }
    }

    View Slide

  30. Une spécification avec paramètres
    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)
    {
    [...]

    View Slide

  31. Composition
    $manyVotes = new HasMoreVoteThan(1000);
    $available = new IsAvailable();
    $byMe = new IsAskedBy(‘gbprod’);
    $isPopular = $available
    ->andX($manyVotes)
    ->andX($byMe->not())
    ;
    $isPopular>isSatifiedBy($question);

    View Slide

  32. Avec symfony ?
    kphoen/rulerz
    happyr/doctrine-specification

    View Slide

  33. Next ?

    View Slide