Domain Event - The Hidden Gem of DDD
-
Upload
henrik-moller-rasmussen -
Category
Technology
-
view
4.357 -
download
1
Transcript of Domain Event - The Hidden Gem of DDD
The Domain Event!The Hidden Gem of DDD
Henrik Møller RasmussenFounder and CTO
The digital daycare
The digital daycare
6 institutions!~1.000 children
Vaughn Vernon: Implementing Domain-Driven DesignEric Evans: Domain-Driven Design: Tackling …
2003 Theoretical
2013!Practical
Domain-Driven Design
Do you DDD?
• Domain Model • Repository • Ubiquitous language • Domain Service • Application Service • Bounded context • Context map • Domain Event • Anti Corruption Layer • And many more…
class Product { ! protected $title; ! protected $price; ! public function setPrice($price) { // .. } ! public function getPrice() { // .. } ! public function setTitle($title) { // .. } ! public function getTitle() { // .. } !}
Is this your domain model?
class ProductController { ! public function addToBasketAction($product) { if ($product->getInStock() <= 0) { $this->redirect(); } ! // Add to basket } }
Where's your business logic?
Let’s build a shop..
Models, Views and Controllers
• Domain models grow into huge classes
• Hard to reason about (mental model)
• Domain models and relations are designed for viewing purposes
• Everything is extremely coupled
• “Big ball of mud”
Package: My.Shop
Proper DDD
Product
CategoryInvoice
Order
EmailCustomer
Reporting
Searching
Inventory
Shipping
Product
CategoryInvoice
Order
EmailCustomer
Reporting
Searching
Inventory
Shipping
Catalog
Inventory
Billing
Search
Reporting
…
…
…
Bounded Contexts / Modules
Catalog
Domain models
Product Category
RepositoriesCatalogService (Application Service)
Inventory
Domain models
Product
RepositoriesInventoryService (Application Service)
There will be more than one class representing a product
• Small models / modules / bounded contexts
• Easy to reason about
• Easy to test
• Loosely coupled
Benefits
Catalog
Inventory
Billing
Search
Reporting
…
…
…
Communication
IntroducingThe Domain Event
So what is a domain event?
• It’s a message …
• .. implemented as a class
• .. published to “the world”
• It’s past tense (e.g. OrderCompletedEvent)
• It’s transactionally coupled to your domain model
• It’s asynchronous
class OrderCompletedEvent { ! public $orderId; ! public $amount; ! public $completedAt; ! public $customerId; !}
Example
class Order { ! public function complete() { $this->completedAt = new \DateTime(); ! $this->eventService->publish( new OrderCompletedEvent(…) ); } !}
Publishing event
Catalog
Inventory
Search
BillingM
essa
ge B
us
EXAMPLE: Order Completed
Why not use signal/slots for that?
1. Customer places order
2. Signal / Slot trigger a foreign context tosend the order confirmation via email
3. Something breaks during persistence of the order.
What now?
Signal / Slot example
START TRANSACTION!UPDATE order … INSERT INTO event_store … COMMIT!!!If this succeeds the event is published to the message bus
Transactionally safe domain events
Catalog
Inventory
Search
BillingM
essa
ge B
us
EXAMPLE: InStock is updated in the inventory
Catalog
Inventory
Search
BillingM
essa
ge B
us
EXAMPLE: Product description updated in the catalog
Benefits of using domain events
• Allows you to integrate bounded contexts with minimal coupling and dependencies.
• Add features to the system with no changes to existing code.
• Get a more responsive system since a lot of functionality is handled asynchronous.
• Get a more robust system. Easier to build fault tolerant system. (Fx. problems with third party services like payment gateways etc.)
UI
Catalog
Inventory
Billing
Search
Reporting
…
…
…
Is it simple to maintain?!Does it perform?!
Yes!No!
(Come see my talk tomorrow about CQRS)
Is it simple to build?! Yes!
Let’s talk Flow
What is a bounded context?
Package?!Subdirectory?!
Its own Flow installation?!Another system?
Could be any of above as long as they are independent and only integrate through domain events (or service calls).
!No sharing of domain models etc.
How do I get started?
https://github.com/agitso/event
• Uses Doctrine’s PostFlush event listener to hook intoDoctrine after persistence and handle domain events.
• The same technique is used in Famly, where we havecurrently handled +500.000 domain events
Recap
• Split your system into smaller modules / bounded contexts
• Put your business logic into the domain models
• Integrate modules with Domain Events (use application service callsfor synchronous interactions).
• Use controllers to orchestrate the views - that is fetch datafrom Application Services and assign to views and similar.NO BUSINESS LOGIC HERE.
Henrik Møller [email protected] Twitter: @heinodk IRC: Come join us at #ddd
The digital daycare