A major project we're working on will be using the Command-Query Responsibility Segregation (CQRS) and Event Sourcing (ES) patterns for its application architecture, and I've spent a few weeks getting my head wrapped around these two ideas. Believe me when I tell you, these patterns are complex enough that the time spent learning them was needed for me to truly understand what was going on. Hopefully this post will save other people some time, because while CQRS and ES are useful, they're pretty dense and difficult to understand if you're seeing them for the first time, but they promise (and deliver) some ENORMOUS benefits once you get past the initial complexity.
Hence, this post. I want to help you get past that initial complexity. So let's get started!
Command-Query Responsibility Segregation
The vast majority of modern application functionality can be summed up in the acronym CRUD:
- Create
- Read
- Update
- Delete
We create objects, read them, modify them, you get the idea. Virtually all functionality in any given app (that isn't trivial) can fall into one of these general categories. CRUD leads to an application model that is relatively simple to understand; such a model may look like this:
Source: Martin Fowler's website
In other words, we have an Application that contains a Model of our data, and uses that Model to query a Database for the data itself. For most applications, this is the correct and even the preferred way of architecting a solution.
While this model works for a great deal of applications, as our needs become more robust, the CRUD model starts to become less and less useful. More intricate applications require a more complex application model, and one possible solution is to use Command-Query Responsibility Segregation (CQRS).
The essence of CQRS is that you use a different model to read the data than you do to modify it. An updated application model would look like this:
Source: Martin Fowler's website
What this allows, among other things, is for the developers to optimize each side (commands and queries) separately for their respective operations. Further, modifications to the models only affect their corresponding applications.
Taken to an extreme, CQRS can enable you to have entire different interfaces, datastores, even complete tech stacks for the query and command sides of you application. Of course, nothing about CQRS says you have to do any of that; the only thing you need to do to satisfy CQRS is to use different models for commands and queries.
Event Sourcing
The second, and distinct, architectural pattern we'll be using is Event Sourcing (ES). In short, Event Sourcing is a different way of thinking about data storage.
Much of the time, we use datastores that reflect the model of our data. Take, for example, one of the models we used in A Simple Checkboxlist in ASP.NET MVC:
For this model, we have database tables for Movie and Genre, related by a many-to-many table (which is not modeled as an entity in Entity Framework; in short, this model has 3 database tables but 2 entities). A great number of databases will use similar models; one table per entity, with relationships and keys and such. In other words, CRUD data models store the data in its current state.
Event Sourcing asks you, the developer, to forget the CRUD model and instead store the changes made to the data using an append-only database store, known as an Event Store. In this architecture, we store all changes made to the data as serialized events, which can be re-run at later time to get us the current state of any object. This pattern allows us to transcend space and time get the state of a given object at any point in the past, which is a great help when debugging certain problems. Further, because all events are serialized, we only need one database table to represent our entire event store (though you can have more).
One point to make here is that Event Sourcing doesn't store the current state of the data. Instead, when a particular object is modified, Event Sourcing re-executes all events on that particular object before making the new change. This means that we could have thousands of events executed every time a change is made (though this can be negated via the use of snapshots, which are "pictures" of the data made at a specific point in time, and are then used as starting points for subsequent events).
Using CQRS and ES Together
While these two patterns (CQRS and ES) are orthogonal, they fit together quite nicely. The Event Store from ES becomes CQRS's Write Model, and the design of the Read Model is irrelevant to how ES behaves. A sample model of how the two patterns fit together can be seen in this diagram:
Source: Introducing Event Sourcing from MSDN
Let's be frank: CQRS/ES is a lot of work to set up, and the benefits of doing so are not always clear. In fact, one of the proponents of this architecture, Martin Fowler, actually recommends not using CQRS unless you have a clear reason to do so. The pattern is most useful in applications that need to scale both horizontally and vertically and don't mind having to deal with a lot of architectural overhead.
For a more in-depth explanation of these ideas, check out Martin Fowler's blog entries for CQRS and Event Sourcing, or read A CQRS Journey from Microsoft Development. In an upcoming series, we're going to take a look at how to implement an application using CQRS and ES in .NET, so be sure to come back for that!
Happy Coding!