A Practical Introduction to Domain Driven Design

A Practical Introduction to Domain Driven Design

B84af63b07f297643ab1fd943c9ac59c?s=128

pelshoff

May 14, 2019
Tweet

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. A Practical Introduction To Domain Driven Design Twitter: @pelshoff @jlammerts

  3. • 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)
  4. None
  5. Approach • Reality • Model of the problem • Model

    of the solution • Working software
  6. Today 1. Discovery 2. Design 3. Implementation 4. Integration

  7. 1/4 Discovery

  8. None
  9. Noun Verb Verb Verb Verb Noun Noun Noun Noun

  10. Context map • Repeat before interpret • Visualize structure •

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

    event • Organizer gets in touch with suppliers • etc.
  12. Testing • Take one sentence • Run it through your

    map
  13. None
  14. Event Event Event Event Event Event Event Event Hot spot

    Decision
  15. Discovery event storm • First interpretation • Visualize time •

    Learn (ubiquitous) language • Learn about issues (hot spots) • First “feeling” for boundaries
  16. 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?
  17. Testing • Take a person • What happens to them

    • Run it through your process
  18. 2/4 Design

  19. Design • Design event storm • Choosing boundaries

  20. None
  21. Command Event Event Event Event Event Event ... Command Decision

    Command
  22. 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
  23. Testing • Take a person • What they do •

    Run it through your process
  24. 3/4 Implementation

  25. None
  26. Command

  27. 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; } ... }
  28. Command • Data Transfer Object • Immutable • Capture intention

  29. Command handler

  30. final class DoVoteHander { public function handleDoVote(DoVote $doVote): void {

    // Voted // DecisionWasPassed // DecisionWasRejected } }
  31. Command handler • Application Entry Point • When command, then

    event(s) • Implementation later
  32. 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
  33. None
  34. Value objects

  35. 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 { /**/ } }
  36. 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; } }
  37. Value objects • Express a value • Define allowed values

    • Are immutable • Are easy to test
  38. Entities

  39. 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; } }
  40. Entities • Have identity • Are more than their attributes

    • Evolve over time • Are slightly harder to test
  41. Services

  42. 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(); } }
  43. Services • Have no identity or attributes (Are not a

    “thing”) • Tackle cross-concern operations • Are harder to test
  44. Repositories

  45. interface VoteRepository{ public function register(DoVote $doVote): void; public function find(Uuid

    $decisionId, Uuid $memberId): Member; }
  46. Repositories • Collection of all objects of a type •

    For now: interface only!
  47. • 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
  48. 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
  49. 4/4 Integration

  50. None
  51. Domain Application Infrastructure Ui, Api’s, tests Layered architecture

  52. Domain Application Database Api’s Ui Tests File system Messaging, etc.

    Hexagonal architecture (Ports & Adapters)
  53. Ui, Api’s, integration- & acceptance tests Application Domain Infrastructure Big

    scary outside world Unit tests
  54. • 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
  55. • 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
  56. 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
  57. Please write two post-its with something you learned Pim Elshoff

    @pelshoff Joop Lammerts @jlammerts