Some thoughts on using CQRS without Event Sourcing

Marco Bürckel
Aug 22, 2018 · 7 min read

In the last couple of years, I had the opportunity to design one or the other CQRS-based system together with my clients. In these projects, I regularly came across one question: How to build a CQRS-based architecture without adapting the Event Sourcing pattern? Especially when a developer team is new to both CQRS and Event Sourcing, trying to adapt these patterns can be quite challenging.

Both CQRS and Event Sourcing are powerful building blocks in architectural design, but they also add complexity and might not fit every situation. Thus, if you want to build a CQRS-based architecture, it is beneficial to know the alternatives to a persistence based on Event Sourcing.

Some blog articles and posts on Stackoverflow refer to CQRS and Event Sourcing as “orthogonal concepts”, which can be applied independently of each other. However, most articles and examples present both concepts baked into one event-based architecture, without discussing any approach to decouple them. Decoupling them is exactly what this article is about.

Do you want to use CQRS, but hesitate about the implications of Event Sourcing? Do you wonder how omitting Event Sourcing might affect a CQRS-based architecture? If the answer to this question is “yes”, this article might be interesting for you.

The Essence of CQRS

Looking at the core concept of the pattern, CQRS states that an application architecture can be divided into two parts:

  • The write-side: A part that modifies the application state by executing commands.

Both concerns are implemented independently of each other. How far the segregation is taken, depends on the concrete architectural design. One may apply it to the logical layers of a system and let both sides share the same database. But often, the segregation is extended to the database level. In that case, write operations and read operations work on different databases.

Image for post
Image for post
Write Operations and Read Operations affecting different Databases

Just like segregating the application in a write-side and a read-side, the persistence layer is then segregated in a write-store and a read-store:

  • The write-store is the database that acts as the source of truth and is affected by executing commands. It either contains the current application state or contains all information needed for rebuilding it. Thus, the write store is optimized towards data integrity and maintaining a correct application state. Using the typical RDBMS way of doing things, this could be achieved by data normalization, integrity checks and transactions. Another way of keeping the application state clean is to make modifying it dead simple. This is the approach the Event Sourcing pattern takes: The state is represented as an append-only sequence of events. Existing data is never modified or removed. This makes it hard to mess things up.

Of course, the data stores need to synchronize. Each modification of the write-store should be reflected within the read-store. This step is called the projection of data. The projection can be implemented in various ways and greatly affects the application architecture. Especially, the choice over projection is closely related to the decision on using Event Sourcing or not. Thus, the next sections will take a closer look at different implementation strategies.

Event-based Projection

Most CQRS implementations utilize event streams as a trigger for data projection. This is an elegant approach, as events naturally describe application state changes. And most (distributed) systems somehow already process them. Processing an application state change usually involves the following steps:

  • A command is instantiated, which represents the action that leads to a certain application state change.

Event-based projection does not necessarily imply an event sourced persistence approach, but there are quite some facts which make it a rather obvious choice:

  • Event-based projection requires persisted events.
    Projections will not always go well. There might be some database connectivity issue or a bug inside an event handler implementation. Eventually, some projections will fail. Thus, the system needs a way to replay event projection. This requires a persistent event store.

As you can see, when using event-based projection, it makes a lot of sense to make the persisted sequence of events the only source of truth. This is exactly what Event Sourcing does. It is the choice of event-based projection that make CQRS and Event Sourcing such a great match. And in such a system, CQRS and Event Sourcing can hardly be called “orthogonal concepts”, because without Event Sourcing, implementing a reliable event-based projection will become significantly harder.

So in case you want to use CQRS without Event Sourcing, what are the alternatives?
From a more abstract point of view, event-based projection is a projection strategy which is based on small deltas. As any projection needs to be replayable, any such strategy requires persisting these deltas as a source of truth. Thus, an alternative projection strategy would not be based on information about deltas at all, but rather on the current application state.

State-based Projection

I came across the term of “state-based projection” in a blog article written by Vladik Khononov [Tackling Complexity in CQRS] and I think it perfectly describes the alternative type of projection strategies that exist besides a delta-based approach:

Instead of projecting small deltas, a state-based projection works on entities as a whole. There are different implementation strategies:

Database Views

When working with a relational database, the read-side of the CQRS-based system can operate on database views. The projection is then entirely handled by the database itself. Given SQL as a query language, this approach offers a good deal of flexibility regarding data aggregation and transformation. Using a Micro-ORM framework like Dapper, it is easy to implement a thin and lightweight read-side while taking full advantage of the CQRS pattern.
However, using database views, the denormalization is limited when it comes to hierarchical data structures.

Entity-based Projection Handlers

In event-based projection, the projection logic is implemented using a set of event handlers. In a similar way, a state-based projection logic can be implemented using entity-based projection handlers:

interface IEntityProjection<TEntity>
{
void Project(TEntity entity);
}

Whenever an entity of type T is changed on the write-side, the projection handlers for type T need to be triggered. In larger systems, this can be done asynchronously in an eventual consistent manner. As Vladik suggests in his aforementioned article, the projection could be triggered by setting either a row-based dirty flag or a row version number that is observed by the projection engine.

Implementing state-based projection does not require events or event handlers. Thus, this approach works well if you want to build a CQRS-based system which does not utilize Event Sourcing. Of course, that does not necessarily mean that there are no events or event handlers in your system design. For example, you still might want to utilize them in scenarios related to communication between system components.

Final Words

In many CQRS-related articles, an event-based projection strategy is assumed without really naming implications or alternatives. However, in my opinion, choosing the right projection strategy is the most important question when it comes to CQRS-based system design. I hope this article helped you to gain some more generic idea about the pattern.

If you have any questions or feedback, just leave me a comment. 😊

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store