CQRS + Event Sourcing – A Step by Step Overview

A common issue I see is understanding the flow of commands, events and queries within a typical CQRS ES based system. The following post is designed to clear up what happens at each step. Hopefully this will help you to reason about your code and what each part does.

CQRS flowCQRS flow

1. A Command is generated from the UI

Typically the UI displays data to the user. The user generates a command by requesting some form of change.

2. The Message Router or Bus receives the command

The message bus is responsible to routing the command to it’s handler.

3. The handler prepares the aggregate root

The handler gets the aggregate root and applies all previous events to it. This brings the AR (aggregate root) up to it’s current state. This is typically very fast, even with thousands of events, however, if this becomes a performance bottleneck, a snapshotting process can be adopted to overcome this issue.

4. The command is issued

Once the AR is up to date the command is issued. The AR then ensures ensures it can run the command and works out what would need to change but DOESN’T  at this point change anything. Instead, it builds up the event or events that need to be applied to actually change it’s state. It then applies them to itself. This part is crucial and is what allows ‘events’ to be re-run in the future. The command phase can be thought of as the behaviour and the apply phase is the state transition.

5. The command handler requests the changes

At this point, assuming no exceptions have been raised, the command handler requests the uncommitted changes. Note that no persistence has actually taken place yet. The domain classes have no dependencies on external services. This makes them much easier to write and ensures they are not polluted by persistence requirements (I’m look at you Entity Framework).

6. The command handler requests persistence of the uncommitted events

Here is when an event storage service comes into play. It’s responsibility is to persist the events and also to ensure that no concurrency conflicts occurs. You can read up on how to do this on a previous post of mine: How to handle concurrency issues in a CQRS Event Sourced system.

7. The events are published onto the Bus or Message Router

Unlike commands which only trigger 1 command handler, events can be routed to multiple de-normalisers. This enables you to build up very flexible optimised read models.

8. De-normalisers build up the Read Model

The concept of a de-normaliser can at first be a little tricky. The problem is that we are all trained to think in ‘entities’, ‘models’ or ‘tables’. Generally these are derived from normalised data and glued together into the form required for the front end. This process often involves complex joins, views and other database query techniques. A de-normaliser on the hand translates certain events into the perfect form required for the various screens in your system. No joins required at all, ever! This is makes reads, very fast  and is the basis behind the claim that this style architecture is, almost, linearly scalable. Most people begin to get twitchy at this point when they realise that duplicate data may exist in the read model. The important thing to remember is that the ‘event stream’ is the only source of truth and there is no (or should be no) accidental duplication within it. This allows you to re-create the entire read model or just parts of it, at will.

9. Data Transfer Objects are persisted to the Read Model

The final phase of the de-normaliser is to persist the simple DTO’s (data transfer objects) to the database. These objects and essentially property buckets and usually contain the ID of the aggregate they are associated with and a version number to aid in concurrency checking. These DTO’s provide the information the user requires, in order to form new commands and start the cycle over again.

All this results in a Highly Optimised Read Side Model

The read/query side is entirely independent of the commands and events, hence CQRS (Command Query Responsibility Segregation). The query side of the application is designed to issue queries against the read model for DTO’s. This process is made entirely trivial due to the de-normalisation of the read data.

A. User requests data

All the data is optimised for reading. This makes querying very simple. If you require values for a ‘type ahead drop down list’, just get the items from an optimised list designed especially for the task. No extra data need be supplied apart from that required to drive the drop down. The helps keeps the weight of the data payload light which in turn helps the appication remain responsive to the user.

B. Simple Data Transfer Objects

The read model just returns simple and slim DTO’s that are, as I said before easy to work with on the front end.

In Conclusion

CQRS’s biggest hurdle is it’s perceived complexity. Don’t be fooled by all the steps above. Unlike a ‘simple CRUD’ approach which starts off simple but quickly gains in complexity over time. This approach remains relatively resistant to increased complexity in the scope of the application.

About the Author Daniel

I'm a professional software engineer of near on 15 years. Lucky enough to work for a small but rapidly growing company in London called Redington. They have given me the technical freedom to learn some cutting edge technologies like CQRS and Event Sourcing. Now I'm sharing what I learn here.

follow me on:
  • Juning Wang says:

    Great read in combination with the previous post on concurrency issue handling in CQRS.

  • Aman Verma says:

    Great article !!!
    I am working on CQRS+ES based project based on Microservices Architecture. This post helped a lot understanding CQRS. Would have been great with a coding example.

  • Denis says:

    Thank you very much for those articles. They really help to understand how things work. Lacking some code samples sometimes. For basic example of transformation to DTO. I couldn’t understand the idea behind persistence part. You persist only the diff of previous and new state of AR into events store? Or you save the actions which should be applied to previous state of AR and the actual received payload from the UI?

    • Daniel says:

      There two different persistence concepts at play here. The source of truth is derived from the event store. This is a store of things that have happened to the domain. The other persistence mechanism is the read model which is essentially a read optimised snapshot of the current state.

  • Denis says:

    Another question is about domain logic. It should be implemented in command handlers or in AR?

    Last question is about read model regeneration. If read database is pretty big and downtime is not a solution, how would you regenerate read model in this case and avoid out-of-sync issue?

    By the way, would be nice to see explanation on failed situations, how to behave if such situations take place at any point of this process.

    How to detect that read models are out of sync?
    As I understand this is not the issue of the pattern, but infrastructure problem instead. Fault tolerance is very important in this pattern as I can see.

    Thank you.

    • Daniel says:

      Domain logic should be done within the AR. There are sometimes questions over what constitutes domain logic. For example, when validating input. I’ve written an article about this which you can find here: How To Validate Commands in a CQRS Application

      Regarding read model regeneration. The only time you may want to regenerate a read model is during some major upgrade or planned downtime. A read model is just like a normal database just much simpler. No need for joins or unions etc.

      Regarding detection of out of sync read models. Ever read model update should be successful. If not then the model is out of sync. You can also detect it via discrepancies with the version number of the domain models and equivalent read models. Although this is trickier as it may be out of sync because multiple users are updating certain specific data.

  • >