CQRS stands for Command Query Responsibility Segregation, and this pattern (or “architectural pattern”) has forever changed my way of designing and building applications.
In my following series on CQRS, I will do my best in explaining why this pattern is one of my favorites and perhaps making it your new favorite as well. Greg Young, Martin Fowler and many other writers on CQRS, has inspired me.
The first time I was introduced to CQRS, I thought I was a hard thing to implement. However, it quickly turned out to be the exact opposite and the little overhead it gives you, will benefit you for years in terms of maintaining code.
I believe people think that CQRS is hard, because it forces you to think about how you structure your code. There is some very specific (few) rules associated with CQRS you will have to get under your skin.
Let us look at a system architecture or pattern many developers know. The classic N-tier system, which I was using prior to CQRS:
While the above pattern is fine for small and simple applications it can quickly turn out to be a nightmare to maintain. The business logic will quickly become a huge mess of system mutation, query methods with side effects all piled up in classes of infinite length.
Let us introduce the CQS (Command and Query Separation) pattern to separate of concerns of the business logic into commands (writing) and queries (reading):
With the introduction of the CQS pattern, we are now required to think about how our domain works. We need to apply commands when we are mutating system state, while applying queries when we are reading data. It is that simple!
Before we continue to implement the CQRS pattern, let us dig into the definitions of commands and queries, as they are equally important in CQRS.
The write side of our system.
Commands are our weapon when we need to mutate state in our system. They are fire-and-forget weapons with no return value.
The read side of our system.
Queries are our weapon when we need to query the system for its current state. Queries are side effects free, which means they should not do any mutation or change of state in the system.
In the above diagram, we have separated our business logic into commands and queries, while still using the same domain model. This an important first step.
To use CQRS more efficiently, we should separate our model into a read model and a write model:
We want to do this, as our read model is most likely different from our write model. The read model may only be a subset of the write model or a combination of various tables.
Although not required, we can possible simplify the read model by having it stored as views in the database and just select them using queries:
By using database views or as pre-calculated materialized views (when dealing with many performance heavy table joins) we are able to gain a performance boost without having to separate our data store completely.
The domain write model is the most important part of any system. This is where we validate the business rules and take decisions before persisting change and updating our read model. This is also the only way to update our read model.
The read model is a different structure; it returns the current state of the system. It needs to be super-fast and while you can physically detach the read model from the write model, in terms of storage server, it is not a requirement you should do so.
Event Sourcing is not a requirement when using CQRS, but the combination of CQRS+ES is a perfect match when designing bigger systems and scalable applications.
Taking advantages of having a separate read- and write models, we can split our storage server into a read- and a write store, in this example an event store:
In this approach our domain write model is producing events for every change in our system, e.g.
CustomerCreatedEvent. The event stores accepts these events in an append-only form and requests the read store to update using projections.
When the event is projecting off the event store, we can append the change in a denormalized format to make our read model super-fast, e.g. using a NoSQL database.
Since our event store is holding all our state change, we can replay all events from the very first event and get the current state of our system. In short that means, at we at any given time we can rebuild our read store from scratch using the events in the event store – we can even go back in time and debug the state of the system. The write model is now the source of truth in our system.
Now we are talking CQRS+Event Sourcing and this is where things get very interesting!
In the next episode of my introduction to CQRS+ES we will use the above diagram as the goal for our CQRS+ES application, but we will start by creating a simple CQRS architecture without using event sourcing.
We will also touch the concept of “Eventual Consistency” using the separated data store approach and finally start writing some code.