What are Domain Events?

Learn about why Domain Events are a very powerful construct to know about and to use when developing your next application.

Mattias Holmqvist

8/21/2020

Learn about why Domain Events are a very powerful construct to know about and to use when developing your next application.

What is an Event?

An event in the context of software development is something that happens around us that we choose to put in to our system as something noteworthy. The most common scenarios include:

  • Storing events for analytics / BI purposes
  • Supporting communication between services by publishing application events
  • Use Event Sourcing to provide a single source of truth

Events are building blocks that have become popular for many use cases. Many technical products base their design on events as a core building block. Just like any other building block or definition it is important to recognize that all events are not equal. First let's look at the properties of events that are ubiquitous regardless of the use case or product involved.

Events are immutable

When something has happened in the world around us it is a fact. We cannot change history and bringing this realization into the design of our software is something that is very helpful for us when developing useful systems. We model the world in a way that resembles how we perceive the world around us. Things happen all the time and there is not much we can do about it. Our systems can help us record and remember the important things and this is why events are a great modeling construct.

An event can only occur once

An event can only happen once. If the same thing happens again later, it is still a different event since it by definition happened after the first occurrence. When you visit your friends house, and you ring the bell three times because they are slow to open the door, there are three different occurrences (events) of the door bell ringing.

Sometimes it can be practical to technically choose to aggregate multiple fine-grained events into a larger event for performance reasons or simply because it logically makes more sense in the application we are developing. Logically it is a good start to separate events and make them as explicit as possible.

Events have already happened

An event always describes something that happened as a fact. This implies that when we look at the event we see it as it happened in the past, and this is why we always write events in past tense. It is a good practice to be strict about this naming convention since it can be easy to confuse events (facts) with requests to a system (intention). Requests can be denied, and we (normally) don't store the history of requests other than for analytical purposes in our systems.

Technical implementation

At its core, an event is a collection of data. It does not hold any behavior or require any specific framework. To use events you need to be able to marshal/unmarshal the data from a serializable format so that they can be sent over the wire or stored to persistent storage. A good option at this point is JSON since it is easy to read, somewhat concise in its format and generally available for all languages. Many implementations also use serialized formats such as Protobuf.

Technically, it is a good practice to include a timestamp of when the event occurred in the event data as well as an unique identifier (UUID is a good choice) to be able to differentiate events from each other. An implementation of an event using JSON could look something like this:

{
  "eventId" : "e4f57d96-994e-4172-a3a6-9820709c87cc",
  "eventType" : "door-bell-rung",
  "timestamp" : "1593168851560",
  "data" : {
    "field1" : "Data here",
    "field2" : "More data"
  }
}

What are Domain Events?

Domain Events are an important concept within Domain-Driven Design. The concept of Domain Events was however not included in Eric Evans' great book about Domain-Driven Design when it was first written, but added as an appendix later, which explains how this focus around events is different from how we used to design systems.

Domain Events are part of your Domain Model

Domain Events are part of your Domain Model, so to define them properly we must put ourselves into the correct context. In Domain-Driven Design we create a model that is valid within a Bounded Context. The context is our solution to a particular problem that we are addressing, so it can be a subsystem or a Microservice or a monolithic application. The core principle of the Domain Model is the same - it is only valid within this context.

Questions to ask while defining your domain events:

  • Does our stakeholders/business care about it?
  • Is it a decision made by our system or another system?
  • Does it encapsulate the why behind the change?

Aggregates create your Domain Events

A Domain Event is an event that is spawned from this model that is a result of a decision within the domain. Within the model our Aggregates have the role of maintaining business rules and this is where we implement decision points in our model, so the Aggregates are also responsible for creating the Domain Events.

This picture illustrates how Domain Events are part of our Domain Model. They are not being sent from other systems and they are not something that the user sends to our system when performing an action. In our terminology, we call these messages commands which describes how they encapsulate the will to make our system perform a task.

Technical implementation

Domain events add little to the generic implementation of other types of events. It is useful to include the originating aggregateId, from where the event was spawned and include the aggregateType and eventType to help consumers of the event to interpret it. They should be serializable just like any other type of event, and you should not include deep references to objects in the code representation of your Domain Events.

{
  "aggregateType" : "payment",
  "aggregateId" : "1d0d12cd-ac5e-470a-8479-b5a871472445",
  "eventType" : "payment-successfully-completed",
  "eventId" : "e4f57d96-994e-4172-a3a6-9820709c87cc",
  "timestamp" : "1593168851560",
  "data" : {
    "customerId" : "ec930ec6-063f-41e2-9ecb-581cf5e2ad06",
    "amountPaid" : 334
  }
}

When is an event not a Domain Event?

To qualify as a Domain Event the event should have a deeper meaning and importance to our business. Everything that happen around us can be described as events, but that does not mean that we need to implement everything that happens in our software.

Examples of things that happen that might not be suitable to model as Domain Events:

  • Something technical (a ButtonClicked, ExceptionThrown etc) happened that we want to record or handle, but it is not described in the ubiquitous language of our domain.
  • Something that happened outside of our bounded context. This could a Domain Event in another system or a different bounded context.
  • Requests to your system. These we define as Commands rather than events, since they can be rejected by our system.

Integrating using Domain Events

You can use Domain Events to integrate services with each other. They are a very useful way to publish information about what happened in different parts of your system and let other parts react, aggregate or perform calculations based on them. There are however some things to consider before going all in using Domain Events as an integration mechanism.

Domain Events are contextual

Remember the Domain Events are really part of the Domain Model from the context where they are spawned. That is where they have their true meaning and publishing events widely to other systems may introduce unwanted coupling between these systems. Since the Domain Events primarily have the role of storing the truth of your applications history.

In a larger system, such as for example an e-commerce system that handles both customer registration, orders, shipping and payments it can be tricky to use Domain Events from one of these contexts in the other contexts. The meaning of the event may not make sense in other contexts. The word order will likely show in all of these contexts but the meaning and importance of the word is different. This is where the knowledge of Context Mapping in Domain-Driven Design is so important ot understand that the Domain Events are part of the Domain Model.

How to get started?

Getting started with Domain Events does not have to be a big change to your system architecture. If you already are designing applications using DDD you can start by also saving events together with your current application state in a part of your application.

When you start adding Domain Events to the mix of your application you might get interested in Event Sourcing, where Domain Events are the central piece of information. Programming with events as the basic building block can take some time to get used to, but the learning is often worth the time, and you will likely notice less friction when serving the needs of the business people with data. You don't have to use Event Sourcing to start using Domain Events in your software. Domain Events can be a useful addition to a more classical DDD-style architecture where they provide an extra dimension of time to certain parts of the application where this is particularly important.

Event Sourcing is an architectural pattern that is applied within a Bounded Context to provide the single source of truth. There are different interpretations of Event Sourcing, but we tend to keep it quite simple:

Event Sourcing is when you use Domain Events to store the state of an Aggregate within a Bounded Context.

This basically means replacing your relational data model (or other data store) with an ever-growing log of Domain Events, which is called an event store. This is the core of Event Sourcing. So to use Event Sourcing you definitely need to understand Domain Events.

For full disclosure, there are few other interpretations of the pattern, but we still think combining Event Sourcing with Domain-Driven Design and Bounded Contexts is the simplest and clearest view on what this pattern is. Mixing in other technical aspects such as pub/sub tends to blur the picture too much.

The transition to Event Sourcing can be a tricky change to make, but there are some big wins that come with it and this transition does not have to be a big-bang. Since Event Sourcing is a pattern that is to be applied within an application/service and not as a system-wide architectural pattern we recommend getting started with a single microservice or application. If your company is new to these ideas it could be wise to let a single team start experimenting with these technologies and ideas.

Common mistakes and pitfalls

Getting started with Domain Events can feel awkward and there are a few things to remember in order to stay on track with your modeling, so your Domain Events bring true value to your software design.

Trying to model everything

The Domain Model should be useful for the problem we're trying to solve. The model is there to enforce the business rules that we have and preferably our architecture should provide a simple enough integration support for us to be able to connect the application with other systems to make it a useful whole.

A common trap that developers fall down into is to try to model everything related to the problem at hand. This is where the distinction of Domain Events and other events can come handy since many times the other events that happen (technical or peripheral) can be regarded as logging events that we can store for analytical purposes only. Often, it is evident what should be a Domain Event when we try to create these technical events from our Aggregate. It becomes quite clear that they do not belong there.

Not breaking out of the CRUD mindset

One of the most common mistakes when starting with Domain Events and with DDD in general is to not go the whole way and figure our what is actually going on in the domain. It is easy to fall into the trap of naming all events SomethingCreated, SomethingUpdated and SomethingDeleted. While not a problem in itself it does not make use of the powerful thing we get by adding the context and meaning to the actual change that the Domain Event represent. You lose the intent of the event and reading the event log later will not provide that much value.

Next steps

To start using Domain Events as a primary building block for your application and use them to their full extent, I recommend learning more about Event Sourcing and then trying out Serialized as a way to get started without any installation of software or management of infrastructure.