CQRS (command and query responsibility segregation) and ES (event sourcing) are two patterns that are easily explained, but not so easily implemented. The patterns are gaining traction and often come together. But many developers have been trained in a classic CRUD way, and don’t always know where to begin. In this series, I’ll not only cover CQRS/ES abstractly, but I’ll provide real code examples to show you it’s really not very difficult.
This first post will, however, focus on the abstract. I’ll explain what CQRS and ES are, what they’re for and why they’re so good together. If you know all this, you might want to skip this post and move to the next one.
What Is CQRS?
CQRS is the acronym of Command Query Responsibility Segregation. The idea is to have a model for writing information to a database, and a separate model for reading from the database.
In most applications we encounter, and definitely those I learnt in school, we write a domain model by creating classes that map to real-world concepts. An object may have certain properties, some of which may contain other objects. For example, a Customer may have a Name, but also a collection of Order objects.
In our code, we’ll often model what a piece of reality looks like: what objects are important for our business problem and the interactions and relations that occur between them.
Then, we will often map this model to a relational database. This way, our application can stop running, but we still have our data when the application is running again. This means, we write this model to the database, so we can read it again later. But it’s always the same model.
In CQRS, we split this up and maintain two models: one for writing and one for reading. That’s it basically. This has or can have several consequences, like different code paths and logic for the read or write side, different storage media, and maybe even entirely different tech stacks!
Event Sourcing
The ES in CQRS/ES is short for event sourcing. Event sourcing is a technique where, instead of storing the current state of your data, you store a series of events, i.e. things that happened.
An example will clarify this. In the CRUD approach, you could create a customer, set the name, change the name, add an order and save that. Stored in a document database, this might look like:
{
id: 145,
name: "Sarah",
orders: [
{
items: [
{
name: "ACME dynamite",
quantity: 2,
unitPrice: 20
}
]
}
]
}
Compare this to the data that would be stored in an event sourced system:
[
{
aggregateId: 145,
type: "CustomerCreated",
data:
{
name: "Sraah"
}
},
{
aggregateId: 145,
type: "CustomerNameChanged",
data:
{
name: "Sarah"
}
},
{
aggregateId: 145,
type: "ItemOrdered",
data:
{
customerName: "Sarah",
items: [
{
name: "ACME dynamite",
quantity: 2,
unitPrice: 20
}
]
}
}
]
Notice how we have a perfect log of what happened to this customer. This is a simple example, but in a more complex application, this can provide very valuable information. Also, if you add meta data like the user who initiated the event and a timestamp, you have a perfect history of who did what with the data.
Why Combine CQRS And ES?
Now that you have a basic understanding of what CQRS and ES are, let’s look into why they are so often combined.
Event sourcing means you will have only one table for your data: the table with all events. A consequence of this is that you only have one way to retrieve data: by getting all events for a given object (e.g. customer) and using those to rebuild the object to its latest state.
But what if we want to display the some data of all objects? For example, what if we want to display a list of the names of all customers? Should we get the events of all customers, rebuild them all? This might not be very performant.
The solution is to use the events only for the write side of the application. For the read side, we will use the aforementioned event handlers to generate multiple read models, depending on our scenario.
For example, we might have a table with all customer names and a table with order totals grouped by city.
Why do we still keep the events for the write side? Because this is our single source of truth. It allows us to rebuild the object with all its properties to the latest state it was in. The events that are stored here are immutable pieces of data that are not to be tampered with.
Next Steps
Hopefully, I have explained CQRS and event sourcing enough for you to understand my next articles. If you still have questions, you can read Martin Fowler’s articles on CQRS and event sourcing.
That being said, it might also become more clear when we dive into the code. CQRS and event sourcing may seem daunting at first, especially if you’ve always done traditional applications with a CRUD-approach. But once you use CQRS/ES, you will see it’s not all that hard (given a few caveats we’ll touch on later).
Note: The next posts will be based on my (surely not complete) experience with CQRS/ES. The very first time I implemented it, I based it on the Exploring CQRS and Event Sourcing book. If you’ve read the book, you will recognize patterns and class names.