Domain Event - The Hidden Gem of DDD

Preview:

Citation preview

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 Rasmussen!hmr@famly.dk Twitter: @heinodk IRC: Come join us at #ddd

The digital daycare