Explained: Domain Events
Chapter 8: Implementing Domain Driven Design
By João Pires (joao.pires@altitude.com)
Agenda ● What Domain Events are, when & why you should use them
● How to model Events and when to uniquely identify them
● Examine a lightweight Publish-Subscriber pattern
● Which components are publishers and which are subscribers
● When an Event Store should be used, how it can be done
● How Events are published to Autonomous Systems
What are Domain Events?
“Something happened that domain experts care about”
Part of the domain model
Represents something that happened (past) in the domain
Activity represented as a series of discrete occurrences
Identify events from domain experts
Hints from domain experts talk:
❏ “When…”
❏ “If that happens…”
❏ “Inform me if…”
❏ “Notify me if…”
❏ “An occurrence of…”
Use Cases
Modelling Events: Naming
● Event and properties names according to
Ubiquitous Language
● Derived from the command that was executed
● Stated in the past tense
Example
Command: BacklogItem.commitTo(Sprint sprint)
Event: BacklogItemCommited
Modelling Events: Properties & behavior
Events are usually Immutable with read only properties
● Timestamp indicates when event occurred
● Identity of the source Aggregate instance or other Aggregate instances involved
● Aggregate State Transition values
Class BacklogItemCommited: DomainEvent {
DateTime OcurredOn;
BacklogItemIdentity BacklogItemId;
SprintIdentity SprintId;
TenantIdentity TenantId;
}
Events with Aggregate characteristics 1/2
Sometimes Events might be modelled as an Aggregate retained in its own
Repository, becoming part of the model structure, and not just a record of some
past occurrence
➔ Events created by direct request from clients,
➔ Response to some occurrence which isn’t a result of executing behaviour of an
Aggregate
Events with Aggregate characteristics 2/2
Still immutable, but must have an unique identity.
➔ Can be published via messaging infrastructure at the same time is stored in
Repository
◆ Same persistence store or global transactions
◆ Or, have forwarding component that sends to infrastructure after storing
Event identity
In Bounded Contexts where an event might be created, published and consumed, there
is rare need to compare events.
Reasons to have identity:
● Event as an Aggregate: identity represented by some properties, like event
name/time, entities involved & timestamp, or might require generating a formal
unique id.
● Event published outside local Bounded Context: when messaging infrastructure
forwards them. Sometimes messages can be delivered more than once
○ Subscribers must detect duplicates and ignore them
Publishing Events
Decoupling - Avoid exposing domain model to messaging infrastructure using
Observer (PublisherSubscriber) pattern
Simplest lightweight solution using a In-memory message bus
● no network involved
● Subscribers execute in the same process with the publisher in same thread
● Subscriber is notified synchronously
● Subscribers run within same transaction
Publishing Events
Publishing Events: Publisher
class BacklogItem: Entity {
[...]
public void CommitTo(Sprint sprint){
DomainEventPublisher.Instance()
.Publish(new BacklogItemCommited(
TenantId, this.Id, SprintId
)
}
}
Subscribing Events
class BacklogItemApplicationService {
public void CommitBacklogItem(Tenant t, BacklogItemId itemId, SprintId
sprintId){
var subscriber = new
DomainEventSubscriber<BacklogItemCommited>(this.EventHandler);
DomainEventPublisher.Instance().Subscribe(subscriber);
var backlogItem = backlogItemRepo.BacklogItemOfId(t, itemId);
var sprint = sprintRepo.SprintOfId(t, sprintId);
backlogItem.CommitTo(sprint);
}
}
Events between remote bounded contexts
Remote Bounded Contexts can receive events from another Bounded Context using
an enterprise messaging middleware: ActiveMQ, RabbitMQ, Akka, NServiceBus, etc
Still uses the Publisher/Subscriber pattern
Using a messaging mechanism between remoted Bounded Contexts implies Eventual
Consistency
● Changes in one model that provoke changes in other models will not be fully
consistent for an elapsed period of time
● Depending on the traffic, multiple systems may never be fully consistent at one
instant of time
Messaging Infrastructure Consistency
Eventual consistency in a messaging solution still requires two mechanisms to be
consistent:
1. The persistence store used by domain model
2. The messaging infrastructure persistence store used to forward the published
events
Required to ensure when model changes are stored, event delivery is guaranteed and
if event delivered it indicates a true situation in the model
Messaging Infrastructure Consistency
How to accomplish consistency between model and event persistence
1. Share the same persistence store: commit model and event message in same local transaction
⬆ good performance ⬇storage in same database, might not be possible
2. Use a global XA transaction (2-phase commit)
⬆ separated storage ⬇not available in some systems, expensive & poor performance
3. Event Store: share storage with model but managed by the Bounded Context not the messaging
infrastructure.
An out-of-band procedure uses the E.S. to publish the stored unpublished Events to the
messaging system
⬆ good performance, local transaction, private messaging system storage, able to provide REST
notification feeds
⬇custom developed Event forwarder, clients must be able to de-duplicate messages
Autonomous services and systems
Domain Events allows enterprise systems to be designed as Autonomous Services
➔ Coarsed-grained business service that operates independently of other services
in the enterprise
➔ Might have multiple technical service interface endpoints for remote clients
➔ Independence achieved by avoiding in-band RPCs
◆ Eases dependence of complete failure / bad performance caused by
unavailable or slow remote systems
Latency Tolerances
Won’t long latency periods before messages are received cause problems?
➔ Don’t assume, ask: How did the same business work before computers?
➔ Many automated systems might tolerate eventually consistency
Example: Subdomain for future team activities planning
Plan Activity
Approve
Activity
Schedule
ActivityActivityCreated ActivityScheduledActivityApproved
If an activity is specified and approved weeks before, and system outage cause Event to
be delayed for some hours, it probably would be a tolerable delay
➔ Other business services might demand higher throughput
◆ High availability/scalability must be designed in autonomous systems and
messaging infrastructure to accommodate latency non-functional requirements
Event Store
The purpose is to store a discrete Event for every executed Model command behaviour
Benefits
1. Use as queue to publish Domain Events through a messaging infrastructure
Allows integrations between Bounded Contexts: remote subscribers react to Events in
their own contexts
2. Feed REST Event notifications to polling clients
3. Examine historical record of result of all commands (trace bugs, audit)
4. Use for trending, forecasting & business analytics
5. Event Sourcing: reconstitute Aggregate instance when retrieved from Repository
6. Undo changes to an Aggregate: preventing / removing / patching events when
reconstituting Aggregates
Event Store: Implementation
● Create a subscriber that receives every Event published in the model
● Subscriber event handler does the following:
○ Serializes the Domain Event instance
○ Places it in a Stored Event Instance with a unique sequence id and the type
of the domain event
○ Persists the Stored Event in a database
Event Store
Forwarding Stored Events
Publishing as RESTful resources 1/3
REST style works best in a Publish/Subscribe scenario when many subscribers are
interested in the same events from a single producer.
Pros
Works well if many clients can go to a single URL to request the same set of notifications,
fanning out to any number of polling consumers (it uses the Pull model)
Cons
Few consumers required to pull from multiple producers for resources to perform a set of
tasks in a sequence. A Polling model isn’t a good choice for many producers to feed
notifications to a consumer where the order of receipt matters.
Forwarding Stored Events
Publishing as RESTful resources 2/3
This approach doesn’t need to keep a set of registered subscribers ⇒ nothing is pushed to
interested parties, but requires for clients to pull notifications from a URI
Clients use HTTP GET to request the current log: contains the latest published notifications.
The response uses Paging, sending a fixed number of events. Previous events in other older
“pages” are considered Archived Logs.
The client applies the events in ascending chronological order, it needs to find in the current
& archived logs all the events not yet consumed by the bounded context.
Archived Log pages are immutable, so they can be cached
Forwarding Stored Events
Publishing as RESTful resources 3/3
Last fetched event was 58
HTTP GET /host/notifications
HTTP/1.1 200 OK
...
Link: <http://host/notifications/61,80>; rel=self
Link: <http://notifications/notifications/41,60>; rel=previous
HTTP GET /host/notifications/41,60
HTTP/1.1 200 OK
Cache-Control: max-age=3600
...
Link: <http://iam/notifications/61,80>; rel=next
Link: <http://iam/notifications/41,60>; rel=self
Link: <http://iam/notifications/21,40>; rel=previous
Forwarding Stored Events
Publishing through Messaging Middleware
A Messaging system allows to easily support Publish/Subscriber and Queues design
patterns.
It uses a Push mechanism to send Event notifications to registered listeners.
A solution using RabbitMQ needs to:
1. Query Domain Events from Event Store not yet published to an Exchange.
Queried Events ordered by sequenced unique id
2. Iterate over the ordered items sending each to the Exchange
3. When Messaging System indicated message is published track that Event as published
It’s the Messaging System that guarantees delivery
Event de-duplication
Scenario
De-duplication is needed where a message published through a messaging
system could be delivered more than once
Example
1. RabbitMQ delivers a message to 1+ subscribers
2. Subscribers process messages
3. Before acknowledgement were received, subscribers fail
4. RabbitMQ delivers unack’ed messages again
Event de-duplication: solution
● Subscriber model operation idempotency: Executing operation 2+ times in
succession => identical executing the same operation 1 time
➔ Might be difficult or impossible
➔ Events out of sequence (latency, retries) could cause errors
● Receiver designed to refuse to execute operation as response to duplicates
➔ Needs tracking messages already handled: persisting topics and unique id’s of all
handled messages
◆ Storing latest handled message not enough due to out of order reception
◆ Needed Database GC mechanism to discard obsolete tracking entries
● Using REST notifications, de-duplication is not a factor: Client receiver save only
most recent id, guarantees applying order
Wrap-up
You’ve learned:
● What Domain Events are, when and why you
should use them
● How to model Events
● How to use a lightweight Publish-Subscriber
component in a model
● Which components are publishers and which are
subscribers
● When an Event Store should be used, how it can
be done
● Publishing outside a Bounded Context using
Messaging middleware
● Questions?
● Experiences to share?
● How to start?
● Middle way?
● Advanced ideias?
Lets discuss

Explained: Domain events

  • 1.
    Explained: Domain Events Chapter8: Implementing Domain Driven Design By João Pires (joao.pires@altitude.com)
  • 2.
    Agenda ● WhatDomain Events are, when & why you should use them ● How to model Events and when to uniquely identify them ● Examine a lightweight Publish-Subscriber pattern ● Which components are publishers and which are subscribers ● When an Event Store should be used, how it can be done ● How Events are published to Autonomous Systems
  • 3.
    What are DomainEvents? “Something happened that domain experts care about” Part of the domain model Represents something that happened (past) in the domain Activity represented as a series of discrete occurrences
  • 4.
    Identify events fromdomain experts Hints from domain experts talk: ❏ “When…” ❏ “If that happens…” ❏ “Inform me if…” ❏ “Notify me if…” ❏ “An occurrence of…”
  • 5.
  • 6.
    Modelling Events: Naming ●Event and properties names according to Ubiquitous Language ● Derived from the command that was executed ● Stated in the past tense Example Command: BacklogItem.commitTo(Sprint sprint) Event: BacklogItemCommited
  • 7.
    Modelling Events: Properties& behavior Events are usually Immutable with read only properties ● Timestamp indicates when event occurred ● Identity of the source Aggregate instance or other Aggregate instances involved ● Aggregate State Transition values Class BacklogItemCommited: DomainEvent { DateTime OcurredOn; BacklogItemIdentity BacklogItemId; SprintIdentity SprintId; TenantIdentity TenantId; }
  • 8.
    Events with Aggregatecharacteristics 1/2 Sometimes Events might be modelled as an Aggregate retained in its own Repository, becoming part of the model structure, and not just a record of some past occurrence ➔ Events created by direct request from clients, ➔ Response to some occurrence which isn’t a result of executing behaviour of an Aggregate
  • 9.
    Events with Aggregatecharacteristics 2/2 Still immutable, but must have an unique identity. ➔ Can be published via messaging infrastructure at the same time is stored in Repository ◆ Same persistence store or global transactions ◆ Or, have forwarding component that sends to infrastructure after storing
  • 10.
    Event identity In BoundedContexts where an event might be created, published and consumed, there is rare need to compare events. Reasons to have identity: ● Event as an Aggregate: identity represented by some properties, like event name/time, entities involved & timestamp, or might require generating a formal unique id. ● Event published outside local Bounded Context: when messaging infrastructure forwards them. Sometimes messages can be delivered more than once ○ Subscribers must detect duplicates and ignore them
  • 11.
    Publishing Events Decoupling -Avoid exposing domain model to messaging infrastructure using Observer (PublisherSubscriber) pattern Simplest lightweight solution using a In-memory message bus ● no network involved ● Subscribers execute in the same process with the publisher in same thread ● Subscriber is notified synchronously ● Subscribers run within same transaction
  • 12.
  • 13.
    Publishing Events: Publisher classBacklogItem: Entity { [...] public void CommitTo(Sprint sprint){ DomainEventPublisher.Instance() .Publish(new BacklogItemCommited( TenantId, this.Id, SprintId ) } }
  • 14.
    Subscribing Events class BacklogItemApplicationService{ public void CommitBacklogItem(Tenant t, BacklogItemId itemId, SprintId sprintId){ var subscriber = new DomainEventSubscriber<BacklogItemCommited>(this.EventHandler); DomainEventPublisher.Instance().Subscribe(subscriber); var backlogItem = backlogItemRepo.BacklogItemOfId(t, itemId); var sprint = sprintRepo.SprintOfId(t, sprintId); backlogItem.CommitTo(sprint); } }
  • 15.
    Events between remotebounded contexts Remote Bounded Contexts can receive events from another Bounded Context using an enterprise messaging middleware: ActiveMQ, RabbitMQ, Akka, NServiceBus, etc Still uses the Publisher/Subscriber pattern Using a messaging mechanism between remoted Bounded Contexts implies Eventual Consistency ● Changes in one model that provoke changes in other models will not be fully consistent for an elapsed period of time ● Depending on the traffic, multiple systems may never be fully consistent at one instant of time
  • 16.
    Messaging Infrastructure Consistency Eventualconsistency in a messaging solution still requires two mechanisms to be consistent: 1. The persistence store used by domain model 2. The messaging infrastructure persistence store used to forward the published events Required to ensure when model changes are stored, event delivery is guaranteed and if event delivered it indicates a true situation in the model
  • 17.
    Messaging Infrastructure Consistency Howto accomplish consistency between model and event persistence 1. Share the same persistence store: commit model and event message in same local transaction ⬆ good performance ⬇storage in same database, might not be possible 2. Use a global XA transaction (2-phase commit) ⬆ separated storage ⬇not available in some systems, expensive & poor performance 3. Event Store: share storage with model but managed by the Bounded Context not the messaging infrastructure. An out-of-band procedure uses the E.S. to publish the stored unpublished Events to the messaging system ⬆ good performance, local transaction, private messaging system storage, able to provide REST notification feeds ⬇custom developed Event forwarder, clients must be able to de-duplicate messages
  • 18.
    Autonomous services andsystems Domain Events allows enterprise systems to be designed as Autonomous Services ➔ Coarsed-grained business service that operates independently of other services in the enterprise ➔ Might have multiple technical service interface endpoints for remote clients ➔ Independence achieved by avoiding in-band RPCs ◆ Eases dependence of complete failure / bad performance caused by unavailable or slow remote systems
  • 19.
    Latency Tolerances Won’t longlatency periods before messages are received cause problems? ➔ Don’t assume, ask: How did the same business work before computers? ➔ Many automated systems might tolerate eventually consistency Example: Subdomain for future team activities planning Plan Activity Approve Activity Schedule ActivityActivityCreated ActivityScheduledActivityApproved If an activity is specified and approved weeks before, and system outage cause Event to be delayed for some hours, it probably would be a tolerable delay ➔ Other business services might demand higher throughput ◆ High availability/scalability must be designed in autonomous systems and messaging infrastructure to accommodate latency non-functional requirements
  • 20.
    Event Store The purposeis to store a discrete Event for every executed Model command behaviour Benefits 1. Use as queue to publish Domain Events through a messaging infrastructure Allows integrations between Bounded Contexts: remote subscribers react to Events in their own contexts 2. Feed REST Event notifications to polling clients 3. Examine historical record of result of all commands (trace bugs, audit) 4. Use for trending, forecasting & business analytics 5. Event Sourcing: reconstitute Aggregate instance when retrieved from Repository 6. Undo changes to an Aggregate: preventing / removing / patching events when reconstituting Aggregates
  • 21.
    Event Store: Implementation ●Create a subscriber that receives every Event published in the model ● Subscriber event handler does the following: ○ Serializes the Domain Event instance ○ Places it in a Stored Event Instance with a unique sequence id and the type of the domain event ○ Persists the Stored Event in a database
  • 22.
  • 23.
    Forwarding Stored Events Publishingas RESTful resources 1/3 REST style works best in a Publish/Subscribe scenario when many subscribers are interested in the same events from a single producer. Pros Works well if many clients can go to a single URL to request the same set of notifications, fanning out to any number of polling consumers (it uses the Pull model) Cons Few consumers required to pull from multiple producers for resources to perform a set of tasks in a sequence. A Polling model isn’t a good choice for many producers to feed notifications to a consumer where the order of receipt matters.
  • 24.
    Forwarding Stored Events Publishingas RESTful resources 2/3 This approach doesn’t need to keep a set of registered subscribers ⇒ nothing is pushed to interested parties, but requires for clients to pull notifications from a URI Clients use HTTP GET to request the current log: contains the latest published notifications. The response uses Paging, sending a fixed number of events. Previous events in other older “pages” are considered Archived Logs. The client applies the events in ascending chronological order, it needs to find in the current & archived logs all the events not yet consumed by the bounded context. Archived Log pages are immutable, so they can be cached
  • 25.
    Forwarding Stored Events Publishingas RESTful resources 3/3 Last fetched event was 58 HTTP GET /host/notifications HTTP/1.1 200 OK ... Link: <http://host/notifications/61,80>; rel=self Link: <http://notifications/notifications/41,60>; rel=previous HTTP GET /host/notifications/41,60 HTTP/1.1 200 OK Cache-Control: max-age=3600 ... Link: <http://iam/notifications/61,80>; rel=next Link: <http://iam/notifications/41,60>; rel=self Link: <http://iam/notifications/21,40>; rel=previous
  • 26.
    Forwarding Stored Events Publishingthrough Messaging Middleware A Messaging system allows to easily support Publish/Subscriber and Queues design patterns. It uses a Push mechanism to send Event notifications to registered listeners. A solution using RabbitMQ needs to: 1. Query Domain Events from Event Store not yet published to an Exchange. Queried Events ordered by sequenced unique id 2. Iterate over the ordered items sending each to the Exchange 3. When Messaging System indicated message is published track that Event as published It’s the Messaging System that guarantees delivery
  • 27.
    Event de-duplication Scenario De-duplication isneeded where a message published through a messaging system could be delivered more than once Example 1. RabbitMQ delivers a message to 1+ subscribers 2. Subscribers process messages 3. Before acknowledgement were received, subscribers fail 4. RabbitMQ delivers unack’ed messages again
  • 28.
    Event de-duplication: solution ●Subscriber model operation idempotency: Executing operation 2+ times in succession => identical executing the same operation 1 time ➔ Might be difficult or impossible ➔ Events out of sequence (latency, retries) could cause errors ● Receiver designed to refuse to execute operation as response to duplicates ➔ Needs tracking messages already handled: persisting topics and unique id’s of all handled messages ◆ Storing latest handled message not enough due to out of order reception ◆ Needed Database GC mechanism to discard obsolete tracking entries ● Using REST notifications, de-duplication is not a factor: Client receiver save only most recent id, guarantees applying order
  • 29.
    Wrap-up You’ve learned: ● WhatDomain Events are, when and why you should use them ● How to model Events ● How to use a lightweight Publish-Subscriber component in a model ● Which components are publishers and which are subscribers ● When an Event Store should be used, how it can be done ● Publishing outside a Bounded Context using Messaging middleware
  • 30.
    ● Questions? ● Experiencesto share? ● How to start? ● Middle way? ● Advanced ideias? Lets discuss