Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

A Practical Introduction To Domain Driven Design Twitter: @pelshoff @jlammerts

Slide 3

Slide 3 text

● 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)

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Approach ● Reality ● Model of the problem ● Model of the solution ● Working software

Slide 6

Slide 6 text

Today 1. Discovery 2. Design 3. Implementation 4. Integration

Slide 7

Slide 7 text

1/4 Discovery

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Noun Verb Verb Verb Verb Noun Noun Noun Noun

Slide 10

Slide 10 text

Context map ● Repeat before interpret ● Visualize structure ● Learn (ubiquitous) language ● First “feeling” for boundaries

Slide 11

Slide 11 text

Organizer Plans Event github.com/pelshoff/ Intro-ddd #User interviews ● Organizer plans event ● Organizer gets in touch with suppliers ● etc.

Slide 12

Slide 12 text

Testing ● Take one sentence ● Run it through your map

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Event Event Event Event Event Event Event Event Hot spot Decision

Slide 15

Slide 15 text

Discovery event storm ● First interpretation ● Visualize time ● Learn (ubiquitous) language ● Learn about issues (hot spots) ● First “feeling” for boundaries

Slide 16

Slide 16 text

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?

Slide 17

Slide 17 text

Testing ● Take a person ● What happens to them ● Run it through your process

Slide 18

Slide 18 text

2/4 Design

Slide 19

Slide 19 text

Design ● Design event storm ● Choosing boundaries

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Command Event Event Event Event Event Event ... Command Decision Command

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Testing ● Take a person ● What they do ● Run it through your process

Slide 24

Slide 24 text

3/4 Implementation

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Command

Slide 27

Slide 27 text

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; } ... }

Slide 28

Slide 28 text

Command ● Data Transfer Object ● Immutable ● Capture intention

Slide 29

Slide 29 text

Command handler

Slide 30

Slide 30 text

final class DoVoteHander { public function handleDoVote(DoVote $doVote): void { // Voted // DecisionWasPassed // DecisionWasRejected } }

Slide 31

Slide 31 text

Command handler ● Application Entry Point ● When command, then event(s) ● Implementation later

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Value objects

Slide 35

Slide 35 text

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 { /**/ } }

Slide 36

Slide 36 text

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; } }

Slide 37

Slide 37 text

Value objects ● Express a value ● Define allowed values ● Are immutable ● Are easy to test

Slide 38

Slide 38 text

Entities

Slide 39

Slide 39 text

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; } }

Slide 40

Slide 40 text

Entities ● Have identity ● Are more than their attributes ● Evolve over time ● Are slightly harder to test

Slide 41

Slide 41 text

Services

Slide 42

Slide 42 text

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(); } }

Slide 43

Slide 43 text

Services ● Have no identity or attributes (Are not a “thing”) ● Tackle cross-concern operations ● Are harder to test

Slide 44

Slide 44 text

Repositories

Slide 45

Slide 45 text

interface VoteRepository{ public function register(DoVote $doVote): void; public function find(Uuid $decisionId, Uuid $memberId): Member; }

Slide 46

Slide 46 text

Repositories ● Collection of all objects of a type ● For now: interface only!

Slide 47

Slide 47 text

● 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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

4/4 Integration

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

Domain Application Infrastructure Ui, Api’s, tests Layered architecture

Slide 52

Slide 52 text

Domain Application Database Api’s Ui Tests File system Messaging, etc. Hexagonal architecture (Ports & Adapters)

Slide 53

Slide 53 text

Ui, Api’s, integration- & acceptance tests Application Domain Infrastructure Big scary outside world Unit tests

Slide 54

Slide 54 text

● 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

Slide 55

Slide 55 text

● 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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Please write two post-its with something you learned Pim Elshoff @pelshoff Joop Lammerts @jlammerts