An Introduction to CQRS Architectural Pattern
Well, it turns out the holiday season might be the only time when I manage to gather enough psychophysical energy to devote myself to some reading and, sometimes, even writing. To be completely honest, though, the writing part would not have been possible if it weren’t for all the time I have been hanging around airports and the extra time kindly offered by Ryanair flight delays. So, while waiting for the next schedule update, why not scribble a bit about what CQRS is and how it can be relevant? First of all, let’s start with some definitions: CQRS stands for Command Query Responsibility Segregation. OK, I must admit, here is one acronym I often fail to remember.
Command query separation was a term coined by Bertrand Miller with the idea of dividing class methods into two categories: queries, which return data without changing any state, and commands, which change the state without returning any data. With this in mind, let’s take a look at CQRS. As said, at its core lies the idea of separating the model that updates information from the model that reads it. In other words, the command-side model deals with creation, update, and deletion operations (CUD), while the query-side deals uniquely with read operations (R).
The actual implementations of CQRS can vary, but usually, command and query are kept as completely separate models, most times linked to separate databases. As a matter of fact, in CQRS implementations, the command model preserves CUD (and some simple R) operations on its main master database, while the query model can be mapped to its separate datastore to perform complicated queries without affecting the efficiency and general operation of the main database. In this scenario, the command model publishes events for each operation performed, which are received by the query-side to keep the two databases in sync.
So, when is CQRS really useful?
CQRS can be a great tool to have on hand whenever dealing with complex queries, usually in a service-based application. It can be a great alternative to balance the downsides of API composition (like in-memory joins of large datasets) when creating queries that span multiple services and their underlying databases. CQRS can help overcome the limitations of using single datastores for all CRUD operations by enabling architects and developers to choose the best database for each query scenario; and, of course, allowing an even better separation of concerns. On the other hand, CQRS brings more complexity due to the additional logic and architectural components; moreover, command-query segregation adds a time lag needed to keep the two sides in sync. It’s clear that there is no silver-bullet architecture and that every pattern has some drawbacks. Like any other architectural pattern, CQRS can be very useful, but only if used in the right context.
If you want to learn more, I recommend starting with this article by Martin Fowler and then deep diving with Microservices Patterns by Chris Richardson, which gives practical examples of how CQRS can be of use.
Happy learning!
Works Cited and Further Reading
Richardson, C. (2019). Microservices patterns: With examples in Java. Manning Publications Co. Fowler, M. CQRS. https://martinfowler.com/bliki/CQRS.html