Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

A Practical Introduction to Domain Driven Design

A Practical Introduction to Domain Driven Design

pelshoff

May 14, 2019
Tweet

More Decks by pelshoff

Other Decks in Research

Transcript

  1. Please tell 2 others: 1. Why you are here today

    2. What you want from today 3. To take a look at github.com/pelshoff/intro-ddd
  2. • has a cult following • works in all cases

    • only works if everyone commits • takes a lot more time • is only for experienced developers • goes well with event sourcing • doesn’t work without event sourcing • • is about documentation • is a new concept • is about strategy • is about tactics • is only for developers • is a hype • is for every project • is all-or-nothing • is about language • DDD... (true / false)
  3. Approach • Reality • Model of the problem • Model

    of the solution • Working software
  4. Context map • Repeat before interpret • Visualize structure •

    Learn (ubiquitous) language • First “feeling” for boundaries
  5. Organizer Plans Event github.com/pelshoff/ Intro-ddd #User interviews • Organizer plans

    event • Organizer gets in touch with suppliers • etc.
  6. Discovery event storm • First interpretation • Visualize time •

    Learn (ubiquitous) language • Learn about issues (hot spots) • First “feeling” for boundaries
  7. github.com/pelshoff/ Intro-ddd #User interviews • Event was planned • Suppliers

    were contacted • etc. Event Decision Hot spot Member was invoiced 14 days passed Invoice was paid Reminder was sent Including Sundays? Visitor arrived Has voting privileges Seated non-voting Seated voting How do we know?
  8. Testing • Take a person • What happens to them

    • Run it through your process
  9. github.com/pelshoff/ Intro-ddd #User interviews • Event was planned • Suppliers

    were contacted • etc. Event Decision Member was invoiced Command Send invoices Reminder was planned
  10. final class DoVote { private $decisionId; ... public function __construct(Uuid

    $decisionId, Uuid $memberId, Answer $answer) { $this->decisionId = $decisionId; $this->memberId = $memberId; $this->answer = $answer; } public function getDecisionId(): Uuid { return $this->decisionId; } ... }
  11. final class DoVoteHander { public function handleDoVote(DoVote $doVote): void {

    // Voted // DecisionWasPassed // DecisionWasRejected } }
  12. Work out some commands in code • Create command DTO’s

    • Create empty command handlers • Add comments for events No implementation! No framework! Get something started One service per command Use and adapt the event storm model Group project files by context
  13. final class Name { private $lastName; private $firstName; private $insertion;

    public function __construct(string $lastName, string $firstName, string $insertion) { $this->lastName = $lastName; $this->firstName = $firstName; $this->insertion = $insertion; $this->nameMustHaveLastName(); } private function nameMustHaveLastName(): void { if (!$this->lastName) { throw InvalidName::becauseLastNameIsMissing(); } } public function getLastName(): string { /**/ } public function getFirstName(): string { /**/ } public function getInsertion(): string { /**/ } }
  14. final class EmailAddress { private $emailAddress; public function __construct(string $emailAddress)

    { $this->emailAddress = $emailAddress; $this->emailAddressMustBeAnActualEmailAddress(); } private function emailAddressMustBeAnActualEmailAddress(): void { if (!filter_var($this->emailAddress, FILTER_VALIDATE_EMAIL)) { throw InvalidEmailAddress::becauseThisIsNotAnEmailAddress(); } } public function asString(): string { return $this->emailAddress; } }
  15. Value objects • Express a value • Define allowed values

    • Are immutable • Are easy to test
  16. final class Member { private $id; private $name; private $emailAddress;

    public function __construct(Uuid $id, Name $name, EmailAddress $emailAddress) { $this->id = $id; $this->name = $name; $this->emailAddress = $emailAddress; } public function getId(): Uuid { /**/ } public function getName(): Name { /**/ } public function setName(Name $name): Attendee { /**/ } public function getEmailAddress(): EmailAddress { /**/ } public function setEmailAddress(EmailAddress $emailAddress): Attendee { $this->emailAddress = $emailAddress; return $this; } }
  17. Entities • Have identity • Are more than their attributes

    • Evolve over time • Are slightly harder to test
  18. final class VotingOnDecision { private $repository; public function __construct(VoteRepository $repository)

    { $this->repository = $repository; } public function handleDoVote(DoVote $doVote): void { $this->memberMayOnlyVoteOnce($doVote); $this->repository->register($doVote); } private function memberMayOnlyVoteOnce(DoVote $doVote): void { try { $this->repository->find($doVote->getDecisionId(), $doVote->getMemberId()); } catch (VoteNotFound $e) { return; } throw VotingFailed::becauseMemberAlreadyVotedOnDecision(); } }
  19. Services • Have no identity or attributes (Are not a

    “thing”) • Tackle cross-concern operations • Are harder to test
  20. • Vendor ◦ PartyCongress ▪ Src • Domain ◦ Congress

    ▪ Congress.php ▪ Decision.php ▪ ListOfDecisions.php ▪ Vote.php ▪ VotingOnDecision.php ▪ VoteRepository.php ◦ Invoice ▪ PaidInvoices.php ◦ Membership ▪ Member.php ▪ MemberRepository.php ▪ Test • Congress ◦ CongressTest.php ◦ DecisionTest.php ◦ VotingOnDecisionTest.php
  21. Work out the domain in code • Value Object: Immutable!

    • Entity: Life cycle! • Domain Service: Cross-concern process! • Repository: Complete set of a type of entity! No database! No browser! No generic subdomain! Focus on the domain Write unit tests Use and adapt the event storm model Group project files by context
  22. • Vendor ◦ PartyCongress ▪ Src • App ◦ Congress

    ▪ DoVote.php ▪ DoVoteHandler.php ◦ Membership • Domain ◦ Congress ▪ Congress.php ▪ Decision.php ▪ ListOfDecisions.php ▪ VoteRepository.php ◦ Membership • Infrastructure ◦ Congress ▪ CachingVoteRepository.php ▪ InMemoryVoteRepository.php ▪ Test • Congress ◦ CongressTest.php ◦ DecisionTest.php ◦ VotingTest.php
  23. • Vendor ◦ PartyCongress ▪ Src • App ◦ Congress

    ▪ DoVoteHandler.php • Domain ◦ Congress ▪ CongressRepository.php ▪ VoteRepository.php • Infrastructure ◦ Congress ▪ InMemoryCongressRepository.php • MyFrameworkOfChoice ◦ Bundles ▪ PartyCongressBundle • Infrastructure ◦ Congress ▪ DbalCongressRepository.php ▪ DbalVoteRepository.php • Ui ◦ Congress ▪ OnlineVotingController.php • Test ◦ Congress ▪ OnlineVotingFrontEndTest.php
  24. Work out the integration in code • Connect the domain

    to your favorite framework, • Or to Plain-Old-C/PHP/Fortran/? • Make something work from UI to DB and back Database Browser End to end tests Group project files by concept