DDD & co.
The data that is created in an application modeled with DDD are domain events. Each event describes a change in state so that the current state corresponds to the sum of the effects of all past events. This state can be saved.
While this works, there is a major drawback as you will miss a great chance: If only the current state is saved, you don't know how it was created. But if you know the past in detail, you can evaluate it and draw conclusions for the future - and determine the current state en passant by replaying all events from the past and reconstructing their changes.
This process is called replay. This way, however, more than just the current state can be determined. If you evaluate only some of the domain events, you can also find out the state of four weeks ago. Or the one from a year ago. Or the one from any other point in time of the past. And, this makes it possible to compare data over time.
A time travel to the past
At the same time, replaying also allows retrospective answers to questions that were initially not even known to be of any interest. If you only ever execute an
UPDATE command for a change, you have no information about the history of your application and your data.
If instead the domain events from the past are available, you can make use of their semantics. Based on the example of the to-do list, this means that questions like these can be answered:
- How much time goes by between noting and ticking off a task?
- How often is a task edited before it is ticked off?
- How many tasks are discarded after they have been edited at least three times?
- How often is ticking off a task undone within 30 seconds?
All these questions can be answered if you have the history of the domain events noted, edited, tickedOff, resumed, discarded and archived.
Event sourcing instead of CRUD
Instead of executing an
UPDATE or even a
DELETE when changes are made, you collect the domain events as deltas in a constantly growing list. This procedure is called event sourcing. Technically, this is very easy to implement, since you only need the two SQL statements
SELECT. A database that works in this way is called event store.
Neither the concept of event sourcing nor the construct of the event store are components of DDD. They can also be used without DDD, just as you can use DDD without event sourcing or an event store. Nevertheless, the building blocks fit well together, which is why it makes sense to combine them with each other.
Incidentally, this approach is not new: Each bank manages its accounts in exactly the same way. Deposits and withdrawals are stored as domain events, and the current balance of your account is determined by the replay of all deposits and withdrawals ever made. A savings account is therefore a perfect example from the real world of practical event sourcing.
Increase performance, reduce storage requirements
One might object that the approach of maintaining a constantly growing list of domain events is theoretically quite interesting, but very costly in everyday life. After all, the memory requirements are increasing and the replay becomes slower with every event. Both objections are correct in themselves, but actually irrelevant.
If you take a closer look at the process of replaying, you will notice that a replay includes almost always the very same events. Since new events are only ever appended to the end of the list of events, its head is always the same. Because there is no
DELETE operation in an event store, this can even be guaranteed.
This means that the result of a replay can not only be saved as a snapshot, but later be reused as the starting point for another replay. This can speed up replays almost arbitrarily, depending on how often snapshots are taken.
Snapshots also make it possible to actually delete all domain events from before a snapshot. This means that you lose the possibility to analyse them individually, but the data can be cleaned up from time to time, for example to save storage space.
Combining DDD and event sourcing
What does it mean in concrete terms if you want to combine DDD and event sourcing? If you want an application to process commands, you need an aggregate that contains the corresponding business logic. As a result, domain events are created that change the state of the aggregate. These events must be stored in an event store.
When an aggregate is loaded, you have to load and replay its domain events from the event store to restore the current state of the aggregate. To ensure that the process does not take longer and longer over time, the event store regularly needs to take snapshots to speed up the replay.
Since most of these tasks are generic, an application developer can focus on developing aggregates, commands, and domain events. These aspects are indeed domain-specific, everything else can be abstracted. The next episode of this series will show how this works.