$30 off During Our Annual Pro Sale. View Details »

Domain-driven Design Workshop

Domain-driven Design Workshop

FWDAYS May 21, 2020

Workshop: Building PHP applications using domain-driven design (DDD) techniques
The workshop is available only for participants of the PHP fwdays’20 conference who purchased a ticket till April 10. The form with registration for the workshop was sent to the email.

The workshop will be held in an online format in Zoom app. Please, install it on your device to follow the workshop. The number of participants is 30.

Workshop from Andrew Cassell is aimed at developers with Knowledge of PHP and object oriented programming. Audience and level: Intermediate and up. The workshop will be held in English.

Building PHP applications using domain-driven design (DDD) techniques results in code that is easier to modify, maintain, test, and makes for a better user experience. In this hands-on tutorial, you will become versed in the best practices for solving problems using domain-driven design in PHP from start to finish. You will learn to:

Discover a ubiquitous language and identify changes in the design of PHP classes, methods, and problem-solving
Use Event Storming build the best software for the client/user
Assemble an incorruptible domain model in PHP
Use bounded contexts and domain events to better organize code and make it more modular
Employ best practices for persisting and accessing entities and aggregate roots in Doctrine, Eloquent, Zend, etc
Use advanced PHP object-oriented techniques to simplify code and reduce state complexity
Plan for change by using the Hexagonal Architecture Pattern
Evaluate when and how to use CQRS and Event Sourcing techniques
Introduce DDD to a “legacy” codebase
Discover recommended resources for learning more about applying DDD in PHP

Andrew Cassell

May 21, 2020
Tweet

More Decks by Andrew Cassell

Other Decks in Programming

Transcript

  1. D ain-D iven
    Design
    Workshop
    D ain-D iven
    Design
    Workshop
    Andrew Cassell
    @alc277 andrewcassell.com

    View Slide

  2. available on

    View Slide

  3. 1
    About
    CURIOSITYSTREAM
    • Founded by John Hendricks,
    founder of the Discovery
    Channel
    • Thousands of documentaries and
    series
    • HD and 4K
    • Available worldwide

    View Slide

  4. 4
    WE ARE HIRING!
    https://jobs.daxx.com/browse-jobs/?search_keywords=curiositystream

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. github.com/cassell

    View Slide

  9. BEER

    View Slide

  10. Good
    Code?

    View Slide

  11. Testable
    SOLID
    Less
    Defensive

    View Slide

  12. View Slide

  13. View Slide

  14. Monolith Microservices Serverless

    View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. View Slide

  19. Domain-Driven
    Design

    View Slide

  20. Domain-Driven
    Design

    View Slide

  21. Common Sense
    Software
    Development

    View Slide

  22. View Slide

  23. View Slide

  24. View Slide

  25. View Slide

  26. 26

    View Slide

  27. 27

    View Slide

  28. View Slide

  29. $car->bark();
    $dog->drive();

    View Slide

  30. View Slide

  31. Encapsulation
    Modeling
    Behavior

    View Slide

  32. Domain

    View Slide

  33. available on

    View Slide

  34. BEER

    View Slide

  35. View Slide

  36. Photo: Kathleen Pierce - Bangor Daily News

    View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. View Slide

  41. View Slide

  42. View Slide

  43. Brewing
    Software

    View Slide

  44. View Slide

  45. View Slide

  46. View Slide

  47. View Slide

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

    View Slide

  49. Source: http://jonclaytonbiz.com/

    View Slide

  50. View Slide

  51. View Slide

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

    View Slide

  53. View Slide

  54. View Slide

  55. View Slide

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

    View Slide

  57. View Slide

  58. YYYYY
    why? why? why? why? why?

    View Slide

  59. Why?
    Why?
    Why?
    Why?
    Why?

    View Slide

  60. Search
    Caluclation
    List
    Automation

    View Slide

  61. DDD !=

    View Slide

  62. View Slide

  63. View Slide

  64. View Slide

  65. View Slide

  66. View Slide

  67. http://www.csharpstar.com/

    View Slide

  68. View Slide

  69. DDD CRUD
    Correctness
    Testability
    Usability
    Maintainability
    Modifiability

    View Slide

  70. View Slide

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

    View Slide

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

    View Slide

  73. Who is
    responsible

    View Slide

  74. View Slide

  75. View Slide

  76. View Slide

  77. View Slide

  78. Ubiquitous
    Language

    View Slide

  79. Ubiquitous Language
    Developers
    Domain
    Experts

    View Slide

  80. View Slide

  81. Ubiquitous
    Language

    View Slide

  82. User
    Brewer
    Employee
    Taster
    Customer

    View Slide

  83. View Slide

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

    View Slide

  85. $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

  86. View Slide

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

    View Slide

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

    View Slide

  89. Ubiquitous Language
    $facilities = new StorageFacilities(); // from container
    $storage = $facilities->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

  90. 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 = new HopQuantity(“Simcoe”,”12%AA”,”.2oz per gallon”);
    Business:

    View Slide

  91. $recipe->dryHop($hop);
    $recipe->addIngredient($hop);
    $recipe->addToBoil($hop);
    $recipe->addToBoilKettle($hop);
    $recipe->addToBoiler($hop);
    $recipe->addFirstWortHop($hop);
    $recipe->addToFermenter($hop);

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  95. […], 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

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

    View Slide

  97. View Slide

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

    View Slide

  99. Inventory
    Marketing
    Finance
    Production
    “Hop”

    View Slide

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

    View Slide

  101. Bounded
    Contexts

    View Slide

  102. Inventory
    Recipes Brewhouse

    View Slide

  103. Slide: Vaughn Vernon

    View Slide

  104. View Slide

  105. Inventory
    Recipes Brewhouse

    View Slide

  106. Inventory
    Recipes Brewhouse

    View Slide

  107. Message
    Inventory
    Recipes Brewhouse

    View Slide

  108. Domain Event
    Inventory
    Recipes Brewhouse

    View Slide

  109. View Slide

  110. View Slide

  111. View Slide

  112. View Slide

  113. View Slide

  114. Personas

    View Slide

  115. adaptivepath.com

    View Slide

  116. 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

  117. View Slide

  118. View Slide

  119. View Slide

  120. View Slide

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

    View Slide

  122. View Slide

  123. View Slide

  124. 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

  125. User Research

    View Slide

  126. Photo: Mathias Verraes

    View Slide

  127. View Slide

  128. Command
    Actor
    Model
    Domain
    Event
    View
    Whatever

    View Slide

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

    View Slide

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

    View Slide

  131. View Slide

  132. View Slide

  133. View Slide

  134. View Slide

  135. View Slide

  136. View Slide

  137. View Slide

  138. View Slide

  139. View Slide

  140. View Slide

  141. https://bit.ly/2LL1Xib

    View Slide

  142. Command
    Actor
    Model
    Domain
    Event

    View Slide

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

    View Slide

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

    View Slide

  145. View Slide

  146. View Slide

  147. View Slide

  148. Command
    Actor
    Model
    Domain
    Event

    View Slide

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

    View Slide

  150. Model
    • Recipe
    • Ingredient
    • Brewer

    View Slide

  151. Command
    Actor
    Model
    Domain
    Event

    View Slide

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

    View Slide

  153. View Slide

  154. View Slide

  155. Water
    profiles
    change daily

    View Slide

  156. Command
    Actor
    Model
    Domain
    Event

    View Slide

  157. View Slide

  158. View Slide

  159. View Slide

  160. Source: Jeff Patton

    View Slide

  161. View Slide

  162. business
    origami

    View Slide

  163. Jess McMullin
    Business Origami

    View Slide

  164. Jess McMullin
    Business Origami

    View Slide

  165. Sean Jalleh

    View Slide

  166. View Slide

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

    View Slide

  168. Domain
    Model

    View Slide

  169. Domain Objects
    Value Objects
    Domain Events
    Entities
    Aggregates

    View Slide

  170. Value Object
    No Identity (Only Values)
    *Immutable
    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

  171. OBJECTS FOR
    ALL THE THINGS

    View Slide

  172. Value
    Objects

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  176. Plain Old PHP Objects
    (POPOs)
    Value Objects

    View Slide

  177. View Slide

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

    View Slide

  179. View Slide

  180. View Slide

  181. View Slide

  182. View Slide

  183. View Slide

  184. View Slide

  185. View Slide

  186. View Slide

  187. View Slide

  188. View Slide

  189. Passed in by
    Reference /
    Pointer

    View Slide

  190. View Slide

  191. View Slide

  192. View Slide

  193. View Slide

  194. Spooky
    Action at a
    Distance

    View Slide

  195. View Slide

  196. View Slide

  197. View Slide

  198. View Slide

  199. View Slide

  200. View Slide

  201. Mutable objects
    depend on state.

    View Slide

  202. View Slide

  203. Mutable objects
    depend on time.

    View Slide

  204. $mutable->function(a,b,c) {
    global $time;
    //…
    }
    $immutable->function(a,b,c) {
    //…
    }

    View Slide

  205. $mutable->getValue() {
    global $time;
    return $value($time);
    }
    $immutable->getValue() {
    return $value;
    }

    View Slide

  206. My pragmatic summary:
    A large fraction of the
    flaws in software
    development are due to
    programmers not fully
    understanding all the
    possible states their
    code may execute in.

    View Slide

  207. Immutability

    View Slide

  208. Function

    View Slide

  209. value
    Mutable

    View Slide

  210. 42
    Mutated

    View Slide

  211. value
    Immutable

    View Slide

  212. value
    Immutable

    View Slide

  213. value
    Immutable

    View Slide

  214. value
    Immutable

    View Slide

  215. Mutable
    Immutable
    Read-Only
    After Creation
    Read & Write

    View Slide

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

    View Slide

  217. View Slide

  218. View Slide

  219. IMMUTABLE
    AND ALWAYS
    VALID
    Value Objects

    View Slide

  220. Value Objects

    View Slide

  221. View Slide

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

    View Slide

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

    View Slide

  224. 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

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

    View Slide

  226. RecipeName
    Example

    View Slide

  227. View Slide

  228. View Slide

  229. View Slide

  230. 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

  231. View Slide

  232. View Slide

  233. 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

  234. View Slide

  235. View Slide

  236. BrewedOn
    Example

    View Slide

  237. View Slide

  238. View Slide

  239. View Slide

  240. Pounds
    Example

    View Slide

  241. View Slide

  242. var_dump(-0.0 > 0); // false
    var_dump(-0.0 < 0); // false
    var_dump(-0.0 === 0.0); // true (float)
    var_dump(-0.0 === 0); // false (int)
    var_dump(-0.0 == false); // true (bool)
    var_dump(-0.0 == null); // true (bool)
    var_dump(-0.0 == “”); // true
    var_dump(-0.0 == "negativezero"); // true (string)

    View Slide

  243. View Slide

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

    View Slide

  245. Eliminate
    Checking
    Value
    Objects

    View Slide

  246. View Slide

  247. View Slide

  248. View Slide

  249. View Slide

  250. What should be
    and Immutable
    Value Object?

    View Slide

  251. Event

    View Slide

  252. Event History

    View Slide

  253. Request

    View Slide

  254. Response

    View Slide

  255. Almost
    Everything

    View Slide

  256. Natural
    Language
    Constructors

    View Slide

  257. Natural
    Language
    Factory Methods

    View Slide

  258. Static
    Constructors

    View Slide

  259. View Slide

  260. View Slide

  261. Resist the Urge
    to Extend

    View Slide

  262. class Pounds extends FloatValue
    {
    //…
    }

    View Slide

  263. class EmailAddress extends StringObject
    {
    //…
    }

    View Slide

  264. View Slide

  265. View Slide

  266. Temperature
    Example

    View Slide

  267. View Slide

  268. View Slide

  269. View Slide

  270. View Slide

  271. View Slide

  272. Composite
    Value Objects

    View Slide

  273. Composite
    Value
    Objects

    View Slide

  274. View Slide

  275. View Slide

  276. View Slide

  277. View Slide

  278. View Slide

  279. View Slide

  280. View Slide

  281. Encoding
    Business Logic in
    Value Objects

    View Slide

  282. Alcohol by
    Volume

    View Slide

  283. View Slide

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

    View Slide

  285. Sugar + Yeast =
    Alcohol + CO2

    View Slide

  286. Sugar - Sugar = Alcohol
    START FINISH

    View Slide

  287. Sugar - Sugar = Alcohol
    START FINISH
    Volume
    Volume

    View Slide

  288. Hydrometer

    View Slide

  289. learntomoonshine.com

    View Slide

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

    View Slide

  291. View Slide

  292. Calibration Temperature
    Minimum Gravity Reading
    Maximum Gravity Reading

    View Slide

  293. View Slide

  294. View Slide

  295. View Slide

  296. 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. View Slide

  307. View Slide

  308. View Slide

  309. View Slide

  310. View Slide

  311. View Slide

  312. View Slide

  313. View Slide

  314. View Slide

  315. View Slide

  316. Как тебе такое, Илон Маск?

    View Slide

  317. View Slide

  318. View Slide

  319. View Slide

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

    View Slide

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

    View Slide

  322. Domain Entities

    View Slide

  323. View Slide

  324. Entities
    Identifiable
    Have State and are Mutable (Lifecycle)
    Operate using Value Objects
    *(Ideally) Storage Agnostic
    *(Ideally) Never in an Invalid State

    View Slide

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

    View Slide

  326. Doctrine
    Zend Hydrator
    *Laravel Eloquent ORM
    “Storage Agnostic”

    View Slide

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

    View Slide

  328. Single Entity
    Entities
    Regular Aggregate
    Contain Other
    Entities

    View Slide

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

    View Slide

  330. 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

  331. View Slide

  332. View Slide

  333. SETTERS
    ARE BAD

    View Slide

  334. View Slide

  335. View Slide

  336. View Slide

  337. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  341. View Slide

  342. View Slide

  343. Doctrine

    View Slide

  344. View Slide

  345. View Slide

  346. View Slide

  347. View Slide

  348. View Slide

  349. View Slide

  350. View Slide

  351. View Slide

  352. View Slide

  353. View Slide

  354. View Slide

  355. View Slide

  356. View Slide

  357. View Slide

  358. View Slide

  359. View Slide

  360. Bounded
    Contexts

    View Slide

  361. Inventory
    Recipes Brewhouse

    View Slide

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

    View Slide

  363. Inventory
    Recipes Brewhouse

    View Slide

  364. Inventory
    Recipes Brewhouse
    Brewers
    Supporting Bounded Context

    View Slide

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

    View Slide

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

    View Slide

  367. Aggregates
    Recipe
    BrewSession
    BeerMenu

    View Slide

  368. View Slide

  369. View Slide

  370. View Slide

  371. View Slide

  372. View Slide

  373. View Slide

  374. Immutable
    “Entity”

    View Slide

  375. View Slide

  376. View Slide

  377. View Slide

  378. View Slide

  379. View Slide

  380. View Slide

  381. Immutable
    Book
    Mutable
    Price

    View Slide

  382. $book->setPrice(16.96);
    $price = new Price($book,15.00)
    $price->setAmount(16.96);
    Mutable
    Immutable

    View Slide

  383. $book->setPrice(16.96);
    $amount = new Amount(16.96, new Currency(‘USD’);
    $price = new BookPrice($book, $amount);
    $price->change(new Amount(15.99, new Currency(‘USD’));
    Mutable
    Immutable

    View Slide

  384. Immutable
    Collections

    View Slide

  385. npm install immutable

    View Slide

  386. <br/>script><br/><script><br/>var map1 = Immutable.Map({ a: 1, b:<br/>2, c: 3 });<br/>var map2 = map1.set('b', 50);<br/>map1.get('b'); // 2<br/>map2.get('b'); // 50<br/>

    View Slide

  387. View Slide

  388. View Slide

  389. Value Object

    View Slide

  390. View Slide

  391. “Immutable”
    Collection
    of Entities

    View Slide

  392. View Slide

  393. View Slide

  394. View Slide

  395. View Slide

  396. View Slide

  397. View Slide

  398. View Slide

  399. $recipe->addGrain()
    $recipe->removeGrain()
    $recipe->updateGrain()

    View Slide

  400. $object->create(x)
    $object->read(x)
    $object->update(x)
    $object->delete(x)

    View Slide

  401. $object->create(x)
    {
    // validate x
    }

    View Slide

  402. $object->read(x)
    {
    // validate x
    }

    View Slide

  403. $object->update(x)
    {
    // validate x
    }

    View Slide

  404. $object->delete(x)
    {
    // validate x
    }

    View Slide

  405. View Slide

  406. View Slide

  407. View Slide

  408. View Slide

  409. Validate Once
    Not Validating Transitions
    Easier to Define the Rules
    Fewer Moving Parts

    View Slide

  410. View Slide

  411. View Slide

  412. Entity’s job is to
    manage state.

    View Slide

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

    View Slide

  414. Task Based
    User Interface

    View Slide

  415. View Slide

  416. View Slide

  417. View Slide

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

    View Slide

  419. View Slide

  420. Security

    View Slide

  421. View Slide

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

    View Slide

  423. Controller
    Domain
    Module

    View Slide

  424. Controller
    Domain
    Package

    View Slide

  425. Controller
    Domain
    Framework

    View Slide

  426. View Slide

  427. View Slide

  428. View Slide

  429. View Slide

  430. Controller
    Domain
    Framework

    View Slide

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

    View Slide

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

    View Slide

  433. View Slide

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

    View Slide

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

    View Slide

  436. Domain
    Events

    View Slide

  437. 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

  438. View Slide

  439. BrewSessionWasPlanned

    View Slide

  440. BrewSessionWasPlanned

    View Slide

  441. View Slide

  442. View Slide

  443. View Slide

  444. View Slide

  445. View Slide

  446. View Slide

  447. View Slide

  448. Inventory
    Recipes Brewhouse

    View Slide

  449. Inventory
    Recipes Brewhouse

    View Slide

  450. Domain Event
    Inventory
    Recipes Brewhouse

    View Slide

  451. Domain Event
    Inventory
    Recipes Brewhouse

    View Slide

  452. Inventory
    Recipes Brewhouse
    Legacy
    Context

    View Slide

  453. Inventory
    Recipes Brewhouse
    Legacy
    Context

    View Slide

  454. Inventory
    Recipes Brewhouse
    Legacy
    Context

    View Slide

  455. Inventory
    Recipes Brewhouse
    Anticorruption Layer
    Legacy
    Context
    Legacy
    Code
    Legacy
    Services

    View Slide

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

    View Slide

  457. Specifications
    Repositories
    Factories
    Fetch
    Build/Create
    Filter/Evaluate
    Services Do Things

    View Slide

  458. View Slide

  459. (EXCEPT CACHING!)

    View Slide

  460. SPECIFICATION

    View Slide

  461. Specifications
    $spec->isSatisfiedBy($object);

    View Slide

  462. View Slide

  463. View Slide

  464. View Slide

  465. Example
    MinimumDiastaticPowerSpecification

    View Slide

  466. View Slide

  467. CQRS

    View Slide

  468. Command Query
    Responsibility
    Segregation
    (Command–query separation)

    View Slide

  469. Write Read

    View Slide

  470. Write
    Model
    Read
    Model(s)

    View Slide

  471. Write
    Domain
    Model
    Read
    Model(s)

    View Slide

  472. Write
    Domain
    Model
    Read
    (Complicated
    SQL Queries)

    View Slide

  473. Controller
    Command Bus
    Handler Handler Handler

    View Slide

  474. Controller
    Command Bus
    Handler Handler Handler
    Request

    View Slide

  475. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  476. View Slide

  477. View Slide

  478. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  479. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  480. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  481. Controller
    Command Bus
    Handler Handler Handler
    Command
    Response

    View Slide

  482. Controller
    Command Bus
    Handler Handler Handler
    Command

    View Slide

  483. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  484. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

  485. Controller
    Command Bus
    Handler Handler Handler
    Response

    View Slide

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

    View Slide

  487. View Slide

  488. Why Do CQRS?

    View Slide

  489. Controller
    Domain
    Framework

    View Slide

  490. Controller
    API (versions?)
    Console Commands

    View Slide

  491. Command Bus
    Command
    Query
    Responsibility
    Segregation

    View Slide

  492. Write
    Domain
    Model
    Read
    Model(s)

    View Slide

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

    View Slide

  494. Event
    Sourcing

    View Slide

  495. View Slide

  496. View Slide

  497. View Slide

  498. Event Sourcing
    • Object Properties are Not Persisted
    • Events Are Persisted to
    Append Only Event Storage

    View Slide

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

    View Slide

  500. Slide: Microsoft

    View Slide

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

    View Slide

  502. Recipe
    Example

    View Slide

  503. Recipe was created with name “New Recipe”
    Recipe name was changed to “php[world] IPhpA”
    11 pounds of 2-Row Malted Barley was added
    2 pounds of Winter Wheat was added
    1 pound of Vienna Malt was added
    8 gallons of water was added
    2 ounces of Centennial Hops for 60 Minutes
    1 ounce of Centennial Hop added at whirlpool

    View Slide

  504. Recipe
    Example

    View Slide

  505. Learning
    More

    View Slide

  506. homebrewersassociation.org

    View Slide

  507. View Slide

  508. View Slide

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

    View Slide

  510. View Slide

  511. View Slide

  512. https://idddworkshop.com/

    View Slide

  513. View Slide

  514. View Slide

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

    View Slide

  516. View Slide

  517. Final Thoughts

    View Slide

  518. View Slide

  519. View Slide

  520. View Slide

  521. View Slide

  522. View Slide

  523. View Slide

  524. DDD Topics Covered
    •Ubiquitous Language
    •Event Storming
    •Modelling
    •Value Objects
    •Entities
    •Aggregates
    •Hexagonal Architecture
    •CQRS
    •Event Sourcing
    @alc277 andrewcassell.com

    View Slide