Domain Event pattern
Domain Events are Events related to Domain changes. Domain Events are things that happen in our Domain that Domain Experts care about. In Domain-Driven Design1, Domain Events are fundamental building blocks that help:
- Communicate with other Bounded Contexts.
- Improve performance and scalability, pushing for eventual consistency.
- Serve as historical checkpoints.
Domain Events are one specific type of Event used for notifying local or remote Bounded Contexts of Domain changes. Examples of Domain Events in a web application are "UserRegistered", "OrderPlaced", "UserRelocated", and "ProductAdded".
Vaughn Vernon definition
An occurrence of something that happened in the domain.2
Eric Evans definition
A full-fledged part of the Domain Model, a representation of something that happened in the domain. Ignore irrelevant domain activity while making explicit the events that the domain Experts want to track or be notified of, or which are associated with state change in the other Model objects.3
Martin Fowler definition
Captures the memory of something interesting which affects the domain.4
Domain Events characteristics :
- Domain Events are ordinarily immutable, as they're a record of something in the past. In addition to a description of the Event, a Domain Event typically contains a timestamp for the time the Event occurred and the identity of Entities involved in the Event. Additionally, a Domain Event often has a separate timestamp indicating when the Event was entered into the system, along with the identity of the person who entered it. When useful, an identity for the Domain Event can be based on some set of these properties. So, for example, if two instances of the same Event arrive at a node, they can be recognized as the same.
- The essence of a Domain Event is that you use it to capture things that can trigger a change to the state of the application you're developing or to another application in your Domain that's interested in those changes. These Event objects are then processed to cause changes to the system and stored to provide an audit log.
- All Events should be represented as verbs in the past tense, as they're things that have been completed in the past — for example, "CustomerRelocated".
Modeling Domain Events :
In order to describe your business domain accurately, you'll have to work closely with domain Experts and define the Ubiquitous Language. This requires crafting domain concepts using Domain Events, Entities, Value Objects, and so on. When modeling Events, name them and their properties according to the Ubiquitous Language, in the Bounded Context where they originated. If an Event is the result of executing a command operation on an Aggregate, the name is usually derived from the command that was executed. It's important that the Event name reflects the past nature of the occurrence.
Persisting Domain Events
Persisting Events is always a good idea. Some of you may be wondering why you shouldn't publish Domain Events directly to a messaging or logging system. This is because persisting them has interesting benefits:
- We can expose our Domain Events to other Bounded Contexts through a REST interface.
- We can persist the Domain Event and the Aggregate changes in the same database transaction before pushing them to an Event Bus.
- Business Intelligence can use this data to analyze, forecast, or trend.
- We can audit our Entity changes.
- For Event Sourcing5, we can reconstitute Aggregates from Domain Events.
Domain events versus integration events6
Semantically, domain and integration events are the same thing: notifications about something that just happened. However, their implementation must be different. Domain events are just messages pushed to a domain event dispatcher, which could be implemented as an in-memory mediator based on an IoC container or any other method.
On the other hand, the purpose of integration events is to propagate committed transactions and updates to additional subsystems, whether they are other microservices, Bounded Contexts or even external applications. Hence, they should occur only if the entity is successfully persisted, since in many scenarios if this fails, the entire operation effectively never happened.
In addition, and as mentioned, integration events must be based on asynchronous communication between multiple microservices (other Bounded Contexts) or even external systems/applications. Thus, the event bus interface needs some infrastructure that allows inter-process and distributed communication between potentially remote services. It can be based on a commercial service bus, queues, a shared database used as a mailbox, or any other distributed and ideally push based messaging system.
Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain
If executing a command related to one aggregate instance requires additional domain rules to be run on one or more additional aggregates, you should design and implement those side effects to be triggered by domain events. As one of the most important use cases, a domain event should be used to propagate state changes across multiple aggregates within the same domain model.
1. “Domain-driven Design”, This content ↩
2. “Implementing Domain-Driven Design”, Vaughn Vernon, https://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon-ebook/dp/B00BCLEBN8 ↩
3. “Domain-Driven Design: Tackling Complexity in the Heart of Software”, Eric Evans, https://www.amazon.com/exec/obidos/ASIN/0321125215/domainlanguag-20 ↩
4. “Domain Event”, Martin Fowler, https://martinfowler.com/eaaDev/DomainEvent.html ↩
5. “Event Sourcing pattern”, This content ↩
6. “Domain events: design and implementation”, docs.microsoft, https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/domain-events-design-implementation ↩