Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Domain-driven Design in PHP - PHP Benelux 2018

Domain-driven Design in PHP - PHP Benelux 2018

Building PHP applications using Domain-driven design techniques results in code that is easier to modify, maintain, and test, and a better user experience. Once you try DDD, you will never design software in the same way again.

In this tutorial, we will start by learning how to build a strong ubiquitous language with stakeholders. Then, we will learn the benefits of encapsulating business logic in value objects using test-driven development.

Next, we will move on to using bounded contexts, entities, and aggregate roots to manage state and protect invariants. We will also cover more advanced topics in the DDD world, such as event sourcing and command query responsibility segregation.

No prior knowledge of domain-driven design required.

https://conference.phpbenelux.eu/2018/sessions/domain-driven-design-in-php/

Andrew Cassell

January 26, 2018
Tweet

More Decks by Andrew Cassell

Other Decks in Technology

Transcript

  1. Domain-Driven
    Design
    Workshop
    Domain-Driven
    Design
    Workshop
    Andrew Cassell
    @alc277 andrewcassell.com

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. Domain-Driven
    Design

    View Slide

  11. Domain-Driven
    Design

    View Slide

  12. View Slide

  13. Common Sense
    Software
    Development

    View Slide

  14. View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. 22

    View Slide

  23. View Slide

  24. Encapsulation &
    Immutability &
    Modeling &
    Behavior

    View Slide

  25. Domain

    View Slide

  26. Domain

    View Slide

  27. BEER

    View Slide

  28. View Slide

  29. View Slide

  30. View Slide

  31. View Slide

  32. Photo: Kathleen Pierce - Bangor Daily News

    View Slide

  33. View Slide

  34. View Slide

  35. View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. View Slide

  41. View Slide

  42. View Slide

  43. View Slide

  44. Brewing
    Software

    View Slide

  45. View Slide

  46. View Slide

  47. View Slide

  48. View Slide

  49. View Slide

  50. View Slide

  51. View Slide

  52. View Slide

  53. View Slide

  54. View Slide

  55. recipe
    hop
    grain
    hop_inventory
    grain_inventory
    recipe_hop_link
    user
    recipe_user_link
    brew_event
    ROLE_USER
    ROLE_ADMIN

    View Slide

  56. Source: http://jonclaytonbiz.com/

    View Slide

  57. View Slide

  58. View Slide

  59. People don't want to buy
    a quarter-inch drill, they
    want a quarter-inch hole.
    Theodore Levitt

    View Slide

  60. View Slide

  61. View Slide

  62. View Slide

  63. #JBTD
    (http://jobstobedone.org/)

    View Slide

  64. View Slide

  65. YYYYY

    View Slide

  66. Why?
    Why?
    Why?
    Why?
    Why?

    View Slide

  67. Search
    Caluclation
    List
    Automation

    View Slide

  68. DDD !=

    View Slide

  69. View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. http://www.csharpstar.com/

    View Slide

  75. View Slide

  76. DDD CRUD
    Correctness
    Testability
    Usability
    Maintainability
    Modifiability

    View Slide

  77. View Slide

  78. DDD BALL OF MUD / CRUD
    Correctness
    Testability
    Usability
    Maintainability
    Modifiability

    View Slide

  79. DDD CRUD/MUD
    Recipe Building Inventory
    Brewhouse Activity Beer Menu / Prices
    Brew Sessions Brewery Website
    Calclations QA Record Keeping

    View Slide

  80. Who is
    responsible

    View Slide

  81. View Slide

  82. View Slide

  83. View Slide

  84. View Slide

  85. Ubiquitous
    Language

    View Slide

  86. Lingua franca

    View Slide

  87. Ubiquitous
    Language

    View Slide

  88. Ubiquitous Language
    Developers
    Domain
    Experts

    View Slide

  89. Ubiquitous
    Language

    View Slide

  90. User
    Brewer
    Employee
    Taster
    Customer

    View Slide

  91. View Slide

  92. 1. Naming Things
    2. Cache Invalidation
    3. Off By One Errors
    Top 10 Reasons
    Programming is Hard

    View Slide

  93. $recipe = BeerRecipe::findOrFail($uuid);

    $hop = HopRepo::where(“name”,”=“,”Simcoe”)->take(1)->get();

    if (!$recipe->hopsArray()->contains(‘hop_id’,$hop->id)) {


    $recipe->hopsArray()->attach($hop->id, [‘weight' => 1.0]);

    }



    $recipe->save();

    View Slide

  94. View Slide

  95. Ubiquitous Language
    $recipe->addGrains($grains);
    Code:
    We need to be able to add a measured amount
    of grain to a recipe.
    Business:

    View Slide

  96. Ubiquitous Language
    $recipe->getEstimatedAlcoholByVolumeABV();
    Code:
    We need to be able to calculate an estimated
    ABV for a recipe.
    Business:

    View Slide

  97. Ubiquitous Language
    $storage = (new StorageFacilities())->findByOneName(“Silo #4”);
    $storage->howMuchOfGrainType(new GrainType(‘Winter Wheat’));
    Business:
    Code:
    We need to know how much Winter Wheat is in
    our storage silo #4.

    View Slide

  98. Ubiquitous Language
    $recipe->addDryHop($hopQuantity,$schedule);
    Code:
    We need to add .2oz of 12% AA per gallon of
    Simcoe hops to a recipe 7 days after the boil is
    complete. This is called dry hopping.
    $schedule = new DryHopSchedule(‘7 Days’);
    $hopQuantity = HopQuantity::(“Simcoe”,”12%AA”,”.2oz per gallon”);
    Business:

    View Slide

  99. @recipe
    Feature: A user should be able to dry hop a recipe
    Scenario: User adds dry hops to recipe
    Given I am authenticated as a user
    And I am on “/recipe/0ef360fd“
    And I press "Add Hops”
    And I fill out form with:
    | Hop Name |
    | Simcoe |
    Then I see “Alpha Acid: 11.5 - 15.0“

    View Slide

  100. $recipe->dryHop($hop);
    $recipe->addIngredient($hop);
    $recipe->addToBoil($hop);
    $recipe->addToBoilKettle($hop);
    $recipe->addToBoiler($hop);
    $recipe->addFirstWortHop($hop);
    $recipe->addToFermenter($hop);
    $recipe->addToMashTun($hop); //fails

    View Slide

  101. $hop = (new HopsSupply(…))->findOneByName(‘Simcoe’);
    $catalog = new RecipeCatalog(…);
    $recipe = $catalog->findOneRecipeByName(‘iPHPA’);
    $recipe->addDryHop($hop, new DryHopSchedule(‘7 Days’));
    $brewers = new Brewers(…);
    $brewer = $brewers->findOneByUsername(‘cassell’);
    $brewSession = $brewer->brew($recipe);
    $brewSession->dryHopsWereAdded($hop, Datetime::now());

    View Slide

  102. $hop = (new HopsSupplyRepo())->findOneByName(‘Simcoe’);
    $catalog = new RecipeCatalogRepository(…);
    $recipe = $catalog->findOneRecipeByName(‘iPHPA’);
    $recipe->addDryHop($hop, new DryHopSchedule(‘7 Days’));
    $brewers = new BrewersRepository(…);
    $brewer = $brewers->findOneByUsername(‘cassell’);
    $brewSession = $brewer->brew($recipe);
    $brewSession->dryHopsWereAdded($hop, Datetime::now());

    View Slide

  103. CRUD/MUD DDD
    Users Brewers
    String RecipeName
    Integer IBU
    Float(7,3) AlphaAcid
    Array of ORM Objects GrainBill
    BeerInventoryRepositoryInterface Menu

    View Slide

  104. View Slide

  105. View Slide

  106. View Slide

  107. $hop = (new HopsSupply())->findOneByName(‘Centennial Pellets’);
    $catalog = new RecipeCatalog(…);
    $recipe = $catalog->findOneRecipeByName(‘iPHPA’);
    $recipe->addDryHop($hop, new DryHopSchedule(‘7 Days’));
    $brewers = new Brewers(…);
    $brewer = $brewers->findOneByUsername(‘cassell’);
    $brewSession = $brewer->brew($recipe);
    $brewSession->dryHopsWereAdded($hop, Datetime::now());

    View Slide

  108. […], we want to establish the idea
    that a computer language is not
    just a way of getting a computer
    to perform operations but rather
    that it is a novel formal medium
    for expressing ideas about
    methodology. Thus, programs
    must be written for people to
    read, and only incidentally for
    machines to execute.

    View Slide

  109. DDD BALL OF MUD/CRUD
    Correctness ✓
    Testability
    Usability
    Maintainability
    Modifiability

    View Slide

  110. View Slide

  111. The Brewer, designed and engraved in the Sixteenth Century, by Jost Amman.

    View Slide

  112. Inventory
    Marketing
    Finance
    Production
    “Hop”

    View Slide

  113. Quantity at a Location
    Flavor
    Expenditure
    Ingredient
    “Hop”

    View Slide

  114. Bounded
    Contexts

    View Slide

  115. Inventory
    Recipes Brewhouse

    View Slide

  116. Slide: Vaughn Vernon

    View Slide

  117. View Slide

  118. Inventory
    Recipes Brewhouse

    View Slide

  119. Inventory
    Recipes Brewhouse

    View Slide

  120. Message
    Inventory
    Recipes Brewhouse

    View Slide

  121. Domain Event
    Inventory
    Recipes Brewhouse

    View Slide

  122. View Slide

  123. View Slide

  124. View Slide

  125. View Slide

  126. View Slide

  127. Personas

    View Slide

  128. adaptivepath.com

    View Slide

  129. Photos: Terry Brown and Gordon Stettinius
    Alice
    Shane P.J.
    Sam
    George
    Male
    Age 32
    Brewer for 3 Years
    Got into brewing after
    the record store he
    worked at closed. Is
    very tech savvy and
    carries an Android.
    Male
    Age 50
    Brewing for 10 Years
    Just Promoted to COO
    Retired civil servant who
    believes software can
    make a brewery for
    regulatory compliant.
    Female
    Age 27
    New Hire
    Library science
    graduate who was
    just hired away
    from the local
    university. iPhone
    user.
    Male
    Age 52
    Librarian for 30 years
    Has been brewing
    beer as long as he can
    remember. Loves beer
    podcasts but is not a
    fan of technology.
    Male
    Age 46
    Brewer for 20 Years
    Loves poetry and
    writing.
    Brewing is just a job to
    pay the bills.

    View Slide

  130. View Slide

  131. View Slide

  132. View Slide

  133. View Slide

  134. https://blog.intercom.io/using-job-stories-design-features-ui-ux/

    View Slide

  135. View Slide

  136. View Slide

  137. 7 Dirty Words When Meeting With a Domain Expert
    1.Session
    2.Repository
    3.Abstract
    4.Interface
    5.Class
    6.Database
    7.Foreign Key

    View Slide

  138. User Research

    View Slide

  139. Photo: Mathias Verraes

    View Slide

  140. Command
    Actor
    Model
    Domain
    Event

    View Slide

  141. Domain Event
    • Something that happens in the
    software.
    • Past Tense

    View Slide

  142. Domain Event
    • Beer Was Brewed
    • Grain Was Added
    • Hops Were Added
    • Brewer Changed Email Address

    View Slide

  143. View Slide

  144. View Slide

  145. View Slide

  146. View Slide

  147. View Slide

  148. View Slide

  149. View Slide

  150. View Slide

  151. View Slide

  152. Command
    Actor
    Model
    Domain
    Event

    View Slide

  153. Command
    • The action that precipitates the event
    • Written in Present Tense

    View Slide

  154. Command
    • Start Brewing Session
    • Add Grain to Recipe
    • Add Hops To Fermenter
    • Change Email Address

    View Slide

  155. View Slide

  156. View Slide

  157. Command
    Actor
    Model
    Domain
    Event

    View Slide

  158. Model
    • Command is acted upon this thing
    • Might Include Supporting Models

    View Slide

  159. Model
    • Recipe
    • Ingredient
    • Brewer

    View Slide

  160. View Slide

  161. Command
    Actor
    Model
    Domain
    Event

    View Slide

  162. Actor
    • Who did it?
    • If you only have one user you might
    not need this

    View Slide

  163. View Slide

  164. View Slide

  165. Command
    Actor
    Model
    Domain
    Event

    View Slide

  166. View Slide

  167. View Slide

  168. business
    origami

    View Slide

  169. Jess McMullin
    Business Origami

    View Slide

  170. Jess McMullin
    Business Origami

    View Slide

  171. Jess McMullin
    Business Origami

    View Slide

  172. Sean Jalleh

    View Slide

  173. View Slide

  174. View Slide

  175. Source: Jeff Patton

    View Slide

  176. View Slide

  177. View Slide

  178. View Slide

  179. View Slide

  180. View Slide

  181. DDD BALL OF MUD/CRUD
    Correctness ✓✓
    Testability
    Usability ✓
    Maintainability
    Modifiability

    View Slide

  182. Domain Objects
    Value Objects
    Domain Events
    Entities
    Aggregates

    View Slide

  183. Value Object
    Immutable
    No Identity (Only Values)
    Hop Name
    Amount Paid
    Temperature
    Entity
    Identifiable
    Mutable
    Lifecycle
    Contains Value Objects
    Line Item
    Brewer
    Water Chemistry
    Aggregate
    Entity
    Responsible For Child Entities
    Transaction Boundary
    Invoice
    Recipe
    Brew Session

    View Slide

  184. Value Objects

    View Slide

  185. Email Address
    Recipe Name
    Date We Brewed On
    Weight
    Temperature
    Value Objects

    View Slide

  186. Value Objects
    Email Address
    Recipe Name
    Date We Brewed On
    Weight
    Temperature
    Ubiquitous
    Language

    View Slide

  187. Value Objects
    EmailAddress
    RecipeName
    BrewedOn
    Pounds
    DegreesFahrenheit
    Email Address
    Recipe Name
    Date We Brewed On
    Weight
    Temperature

    View Slide

  188. Not Just Static Typing
    https://github.com/Fiedzia/type-system-research/blob/master/README.md
    Value Objects

    View Slide

  189. Immutable

    View Slide

  190. Immutable
    Avoid Spooky
    Action at a
    Distance

    View Slide

  191. ALWAYS
    VALID
    Value Objects

    View Slide

  192. Value Objects

    View Slide

  193. “Gateway Drug to
    Test Driven Development”
    Value Objects

    View Slide

  194. “Gateway Drug to
    Test Driven Development”
    Value Objects
    #MYTESTSDONTPASS

    View Slide

  195. Plain Old PHP Objects
    (POPOs)
    Value Objects

    View Slide

  196. Plain Old PHP Objects (POPOs)
    • Declare Class Properties as Private
    • No Setters (behaviors will return new)
    • No References to Mutable Objects
    • Throw Exceptions in Constructor
    Value Objects

    View Slide

  197. Only depend on
    scalars or other value
    objects.
    Value Objects

    View Slide

  198. They are not
    dependencies that
    you inject.
    Value Objects

    View Slide

  199. RecipeName
    Example

    View Slide

  200. View Slide

  201. View Slide

  202. View Slide

  203. View Slide

  204. cassell:beeriously cassell$ docker run --rm --interactive --tty --network beeriously_default --volume `pwd`:/app
    --user : --workdir /app beeriously_php-fpm /app/vendor/bin/phpunit --configuration /app/src/Tests/Unit/
    phpunit.xml.dist
    PHPUnit 6.4.3 by Sebastian Bergmann and contributors.
    FEE 3 / 3 (100%)
    Time: 2.34 seconds, Memory: 4.00MB
    There were 2 errors:
    1) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testGetter
    Error: Class 'Beeriously\Domain\Recipe\RecipeName' not found
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:20
    2) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testToString
    Error: Class 'Beeriously\Domain\Recipe\RecipeName' not found
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:26
    --
    There was 1 failure:
    1) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testEmptyFails
    Failed asserting that exception of type "Error" matches expected exception
    "Beeriously\Domain\Recipe\InvalidRecipeNameException". Message was: "Class 'Beeriously\Domain\Recipe\RecipeName'
    not found" at
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:15
    .
    ERRORS!
    Tests: 3, Assertions: 1, Errors: 2, Failures: 1.

    View Slide

  205. View Slide

  206. cassell:beeriously cassell$ docker run --rm --interactive --tty --network
    beeriously_default --volume `pwd`:/app --user : --workdir /app beeriously_php-fpm /app/
    vendor/bin/phpunit --configuration /app/src/Tests/Unit/phpunit.xml.dist
    PHPUnit 6.4.3 by Sebastian Bergmann and contributors.
    .EE 3 / 3 (100%)
    Time: 1.56 seconds, Memory: 4.00MB
    There were 2 errors:
    1) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testGetter
    Error: Call to undefined method Beeriously\Domain\Recipe\RecipeName::getValue()
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:21
    2) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testToString
    Object of class Beeriously\Domain\Recipe\RecipeName could not be converted to string
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:27
    ERRORS!
    Tests: 3, Assertions: 2, Errors: 2.
    cassell:beeriously cassell$

    View Slide

  207. View Slide

  208. docker run --rm --interactive --tty --network beeriously_default --volume `pwd`:/app --
    user : --workdir /app beeriously_php-fpm /app/vendor/bin/phpunit --configuration /app/
    src/Tests/Unit/phpunit.xml.dist
    PHPUnit 6.4.3 by Sebastian Bergmann and contributors.
    ..E 2 / 3 (67%)
    Time: 292 ms, Memory: 4.00MB
    There was 1 error:
    1) Beeriously\Tests\Unit\Domain\Recipe\RecipeNameTest::testToString
    Object of class Beeriously\Domain\Recipe\RecipeName could not be converted to string
    /app/src/Tests/Unit/Domain/Recipe/RecipeNameTest.php:27
    ERRORS!
    Tests: 35, Assertions: 78, Errors: 1.
    make: *** [unit] Error 2
    cassell:beeriously cassell$

    View Slide

  209. View Slide

  210. cassell:beeriously cassell$ docker run --rm --interactive --tty --network
    beeriously_default --volume `pwd`:/app --user : --workdir /app
    beeriously_php-fpm /app/vendor/bin/phpunit --configuration /app/src/Tests/
    Unit/phpunit.xml.dist
    PHPUnit 6.4.3 by Sebastian Bergmann and contributors.
    ... 3 / 3
    (100%)
    Time: 192 ms, Memory: 4.00MB
    OK (3 tests, 4 assertions)

    View Slide

  211. View Slide

  212. View Slide

  213. BrewedOn
    Example

    View Slide

  214. View Slide

  215. View Slide

  216. View Slide

  217. Pounds
    Example

    View Slide

  218. View Slide

  219. View Slide

  220. View Slide

  221. $poundA->reduceBy($poundB);

    View Slide

  222. Eliminates Checking
    Value Objects

    View Slide

  223. View Slide

  224. Static
    Constructors

    View Slide

  225. Natural
    Language
    Constructors

    View Slide

  226. View Slide

  227. View Slide

  228. Temperature
    Example

    View Slide

  229. View Slide

  230. View Slide

  231. View Slide

  232. View Slide

  233. View Slide

  234. Composite
    Value Objects

    View Slide

  235. Full Name
    First Name + Last Name

    View Slide

  236. View Slide

  237. Encoding
    Business Logic in
    Value Objects

    View Slide

  238. View Slide

  239. View Slide

  240. Amount of
    Alcohol

    View Slide

  241. View Slide

  242. ABV

    View Slide

  243. Sugar + Yeast =
    Alcohol + CO2

    View Slide

  244. Sugar + Yeast =
    Alcohol + CO
    2
    C H O ->2C H OH + 2CO
    6 12 6 2 5 2

    View Slide

  245. Sugar + Yeast =
    Alcohol + CO2

    View Slide

  246. Sugar + Yeast =
    Alcohol + CO2

    View Slide

  247. Sugar - Sugar = Alcohol
    START FINISH

    View Slide

  248. Sugar - Sugar = Alcohol
    START FINISH
    Volume
    Volume

    View Slide

  249. Specific Gravity

    View Slide

  250. View Slide

  251. Hydrometer

    View Slide

  252. View Slide

  253. learntomoonshine.com

    View Slide

  254. Michael L. Hall - Zymurgy, Summer 1995, vol. 18, no. 2

    View Slide

  255. View Slide

  256. View Slide

  257. View Slide

  258. View Slide

  259. View Slide

  260. View Slide

  261. View Slide

  262. View Slide

  263. View Slide

  264. View Slide

  265. View Slide

  266. View Slide

  267. View Slide

  268. View Slide

  269. View Slide

  270. View Slide

  271. View Slide

  272. View Slide

  273. View Slide

  274. DDD CRUD/MUD
    RecipeName String
    Temperature Float(7,3)
    DateBrewed DateTime
    Gravity Float(7,3)
    ABV Function + Validation?

    View Slide

  275. DDD BALL OF MUD/CRUD
    Correctness ✓✓
    Testability ✓
    Usability ✓
    Maintainability
    Modifiability

    View Slide

  276. View Slide

  277. Entities

    View Slide

  278. Identifiable
    Have State and are Mutable (Lifecycle)
    Never in an Invalid State
    Operate using Value Objects
    No Security or Permission Checks
    *(Ideally) Storage Agnostic
    Entities

    View Slide

  279. DO AS MUCH AS
    YOU CAN IN
    VALUE OBJECTS!

    View Slide

  280. Doctrine Mappings
    Doctrine Annotations
    Laravel Eloquent ORM
    “Storage Agnostic”

    View Slide

  281. BEHAVIOR FIRST!
    STORAGE SECOND!
    “Storage Agnostic”

    View Slide

  282. Single Entity
    Entities
    Regular Aggregate
    Contain Other
    Entities

    View Slide

  283. Brewer
    Grain
    Hops
    BeerOnTap
    Entity Types
    Regular Aggregate
    Invoice
    Recipe
    BrewSession
    BeerMenu

    View Slide

  284. Making an Entity: Brewer
    Identifiable ID (UUID)
    Mutable
    $brewer->changeUsername
    $brewer->changeName
    $brewer->changeEmail
    Never in an Invalid State __construct
    Operate Using Value Objects FullName, EmailAddress, …

    View Slide

  285. View Slide

  286. SETTERS
    ARE BAD

    View Slide

  287. View Slide

  288. View Slide

  289. View Slide

  290. View Slide

  291. Calling two setters in a row
    on the same object
    Missing a Concept?

    View Slide

  292. Calling two methods in a row
    on the same object
    Missing a Concept?

    View Slide

  293. Passing more than one
    parameter to a method
    Missing a Concept?

    View Slide

  294. View Slide

  295. View Slide

  296. Doctrine

    View Slide

  297. View Slide

  298. View Slide

  299. View Slide

  300. View Slide

  301. View Slide

  302. View Slide

  303. View Slide

  304. View Slide

  305. View Slide

  306. Bounded
    Contexts

    View Slide

  307. Inventory
    Recipes Brewhouse

    View Slide

  308. Inventory
    Recipes
    Brewhouse
    Recipe\Grain
    Inventory\Grain
    Brewing\BrewSession\Grain

    View Slide

  309. Inventory
    Recipes Brewhouse

    View Slide

  310. Inventory
    Recipes Brewhouse
    Brewers
    Supporting Bounded Context

    View Slide

  311. Mathias Verraes - Mathias Verraes - Emergent Boundaries
    https://www.youtube.com/watch?v=ECM1rPYxvD4

    View Slide

  312. • Entities
    • Manages Child Entities
    • Transactional Boundary
    • The Easiest Models to Identify
    Aggregates

    View Slide

  313. Aggregates
    Recipe
    BrewSession
    BeerMenu

    View Slide

  314. View Slide

  315. View Slide

  316. View Slide

  317. View Slide

  318. View Slide

  319. View Slide

  320. View Slide

  321. View Slide

  322. DDD BALL OF MUD/CRUD
    Correctness ✓✓
    Testability ✓✓
    Usability ✓
    Maintainability ✓✓
    Modifiability ✓

    View Slide

  323. Business
    Rules in a
    Specification

    View Slide

  324. View Slide

  325. View Slide

  326. View Slide

  327. DDD BALL OF MUD/CRUD
    Correctness ✓✓✓
    Testability ✓✓
    Usability ✓
    Maintainability ✓✓
    Modifiability ✓

    View Slide

  328. Task Based
    User Interface

    View Slide

  329. View Slide

  330. View Slide

  331. View Slide

  332. DDD BALL OF MUD/CRUD
    Correctness ✓✓✓
    Testability ✓✓
    Usability ✓✓
    Maintainability ✓✓
    Modifiability ✓

    View Slide

  333. View Slide

  334. Security

    View Slide

  335. Domain
    (Business Logic)
    Application
    Services
    Controller
    Persistence
    Event/Command Bus
    Security
    Templates

    View Slide

  336. Controller
    Domain
    Framework

    View Slide

  337. View Slide

  338. View Slide

  339. View Slide

  340. View Slide

  341. Controller
    Domain
    Framework

    View Slide

  342. Mathias Verraes - Decoupling the Model from the Framework at Laracon EU 2014
    https://www.youtube.com/watch?v=QaIGN_cTcc8

    View Slide

  343. Ruby Midwest 2011 - Keynote: Architecture the Lost Years by Robert Martin
    https://www.youtube.com/watch?v=WpkDN78P884

    View Slide

  344. View Slide

  345. View Slide

  346. Domain
    (Business Logic)
    Application
    Services
    Controller
    Persistence
    Event/Command Bus
    Security
    Templates

    View Slide

  347. DDD BALL OF MUD/CRUD
    Correctness ✓✓✓
    Testability ✓✓
    Usability ✓✓
    Maintainability ✓✓✓
    Modifiability ✓

    View Slide

  348. Domain
    Events

    View Slide

  349. Domain Events
    • Part of the Core Domain
    • Happened In The Past
    • Important Enough To Record (Persist)
    • Important Enough To Concern Other Bounded Contexts
    • Immutable Value Objects
    • Do Not Contain Entities or Other Mutable Objects
    • Can Be Created in an Entity

    View Slide

  350. View Slide

  351. BrewSessionWasPlanned

    View Slide

  352. BrewSessionWasPlanned

    View Slide

  353. View Slide

  354. View Slide

  355. View Slide

  356. View Slide

  357. View Slide

  358. View Slide

  359. View Slide

  360. DDD BALL OF MUD/CRUD
    Correctness ✓✓✓
    Testability ✓✓
    Usability ✓✓
    Maintainability ✓✓✓
    Modifiability ✓✓

    View Slide

  361. View Slide

  362. Command Query
    Responsibility
    Segregation

    View Slide

  363. CQRS

    View Slide

  364. Write Read

    View Slide

  365. Write
    Model
    Read
    Model(s)

    View Slide

  366. Write
    Domain
    Model
    Read
    Model(s)

    View Slide

  367. Write
    Domain
    Model
    Read
    (Complicated
    SQL Queries)

    View Slide

  368. Controller
    Command Bus
    Handler Handler Handler

    View Slide

  369. Controller
    Command Bus
    Handler Handler Handler
    Request

    View Slide

  370. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  371. View Slide

  372. View Slide

  373. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  374. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  375. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  376. Controller
    Command Bus
    Handler Handler Handler
    Command
    Response

    View Slide

  377. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  378. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  379. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  380. Controller
    Command Bus
    Handler Handler Handler
    Response
    Command

    View Slide

  381. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  382. https://gnugat.github.io/
    2016/05/11/towards-cqrs-
    command-bus.html

    View Slide

  383. View Slide

  384. View Slide

  385. Controller
    Command Bus
    Handler Handler Handler
    Response
    Command

    View Slide

  386. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  387. View Slide

  388. View Slide

  389. View Slide

  390. View Slide

  391. Why Do CQRS?

    View Slide

  392. Controller
    Domain
    Framework

    View Slide

  393. Controller
    API (versions?)
    Console Commands

    View Slide

  394. Command Bus
    Command
    Query
    Responsibility
    Segregation

    View Slide

  395. Write
    Domain
    Model
    Read
    Model(s)

    View Slide

  396. Event
    Sourcing

    View Slide

  397. View Slide

  398. View Slide

  399. View Slide

  400. Event Sourcing
    • Object Properties are Not Persisted
    • Events Are Persisted to 

    Append Only Event Storage

    View Slide

  401. • Avoids Data Mapping
    • Avoids Object-relational Impedance Mismatch
    • Reduces Database Table Counts (Related Tables)
    • Potentially Reduces Model Counts
    Event Sourcing

    View Slide

  402. Slide: Microsoft

    View Slide

  403. Libraries
    • https://github.com/broadway
    • https://github.com/prooph
    • https://github.com/szjani/predaddy

    View Slide

  404. Recipe
    Example

    View Slide

  405. Learning
    More

    View Slide

  406. homebrewersassociation.org

    View Slide

  407. View Slide

  408. View Slide

  409. DEV BOOK CLUB
    https://www.youtube.com/user/devbookclub

    View Slide

  410. View Slide

  411. View Slide

  412. View Slide

  413. View Slide

  414. View Slide

  415. DDDinPHP
    Google Group
    http://DDDinPHP.org

    View Slide

  416. Final Thoughts

    View Slide

  417. View Slide

  418. View Slide

  419. View Slide

  420. View Slide

  421. Inventory
    Recipes Brewhouse

    View Slide

  422. Inventory
    Recipes Brewhouse
    Legacy
    Context

    View Slide

  423. View Slide

  424. View Slide

  425. View Slide

  426. Value
    Objects
    “Light”

    View Slide

  427. Andrew Cassell @alc277 andrewcassell.com
    Immutability to Save an
    Ever-Changing World

    View Slide

  428. https://joind.in/talk/93cfd
    DDD Topics Covered
    •Ubiquitous Language
    •Event Storming
    •Modelling
    •Value Objects
    •Entities
    •Aggregates
    •Hexagonal Architecture
    •CQRS
    •Event Sourcing

    View Slide