Event Sourcing is a really interesting pattern in software engineering. It is an alternative approach to maintaining the state of a domain model and managing its persistence.
There’s a wealth of great material around this pattern and how to use it for building software. If you’d like more information then I’ve included a section at the end of this post with a list of useful resources.
In this post, rather than explain all the details of Event Sourcing, I want to just focus on what I think is the essence of this pattern. Armed with this information you can then go off and explore the subject in more detail.
Why Event Sourcing?
Consider a more traditional software architecture: you create a domain model that represents the current state of the system and you manipulate the state by mutating the model. The domain model is persisted into the database using a set of CRUD (create, read, update and delete) operations.
For many simple domains, this pattern works quite nicely, but what happens when things start to get more complex:
- When there’s a requirement to track the history of changes to the domain?
- When operating in a regulated environment where all domain state changes should be immutable?
- When there’s a need to be able to replay previous domain changes in order to populate other systems or databases?
Typical approaches to these requirements often end up adding history tables into the database, and have these be automatically populated by triggers or stored procedures on each domain model change. There are then additional persistence layers that allow for reading and processing the data in these history tables. Typically this ends up growing into a complex set of parallel tables and code that becomes costly to maintain and enhance.
So is there another way we can model our domain and persistence to more naturally support these extended requirements?
Enter the Event Sourcing pattern
In Event Sourcing, we treat changes to the domain model as a sequence of individual Events. Each of these events is named for an action that happened to the domain and contains the data related to that action. For example, the events related to a customer could be:
- CustomerCreated (id, forename, surname, email)
- CustomerEmailChanged (id, newEmail)
- CustomerAddressAdded (id, addressDetails)
- CustomerPaymentDetailsAdded (id, cardNumber, expiryDate, nameOnCard, ccv)
- etc.
Rather than unpacking the events into normalised database tables with individual data fields, with event sourcing we just directly store the events themselves in a time-ordered store. Each event is fully immutable and thus acts as both an audit trail and change history for the domain.
When we want to get the current state of any object in the domain, we start with an uninitialised instance and then we load and replay each of the events for that entity in order. After replaying all of the events the object represents the current state of the entity and can then be queried as we would any normal object. Changes to the object are applied by generating another Event.
For many objects, hydrating them by just replaying a small number of events works out just fine. However, some objects might have many updates and can accumulate a large number of events. Replaying these each time can be inefficient so, for these cases, we can take periodic snapshots of state. We then just start from this snapshot version and replay only those new events since the snapshot was taken.
Having a store of all the events that have ever occurred against the domain model also makes it possible to support other replay options, such as repopulating a view model in a CQRS system or as a source of test fixture configuration.
Summary
From the above we can see that Event Sourcing offers an elegant approach to designing and building systems where we need an immutable audit trail and a full history of state changes. It provides an alternative way to thinking about how to model a domain and plays really well with CQRS.
Resources
Here’s a list of useful Event Sourcing resources that you can use to continue your journey:
- Martin Fowler’s Overview of Event Sourcing
- Azure Event Sourcing Cloud Design Pattern
- Event Store Blog
- Axon Event Sourcing Overview
- AxonIQ - Framework and Server