CQRS: When You Shouldn’t Use It (Or At Least Think Twice)
Hi all! This is my first post for Intelygenz and I would like to take this opportunity to talk about CQRS (Command-Query Responsibility Segregation). There are plenty of articles and books out there that explain how this pattern works, but in this article, I’d like to talk about it from another point of view. Here, I want to talk about the various scenarios where it shouldn’t be used.
One of the main responsibilities of any developer who works on the design of a system is to find a solution that best achieves its objectives while minimising costs and complexity. CQRS is a widely extended pattern, and in some cases it is used unnecessarily, adding unnecessary complexity to the system.
What Is CQRS?
Let’s start with a little reminder of what CQRS is. Put simply, it is a design pattern that consists of dividing our system into two subsystems:
Command Model: this is responsible for processing all requests that modify the estate of the system.
Query Model: this is responsible for processing all requests that extract information from the system, but don’t modify the status of the system. These are read only operations.
A simplified scheme of this pattern could be this:
As previously mentioned, this is a simplified definition of CQRS and in this post, I won’t be going into further detail on it. Here, I’ll be identifying cases where it should and should not be used.
CQRS and DDD
The CQRS pattern is closely related to the use of Domain Driven Design (DDD) because the philosophy of both are very similar. Following DDD, we must divide our system and clearly define the interfaces between them.
When applying CQRS in these types of systems, it helps to reduce the overall complexity and achieve better results.
When deciding whether to use CQRS or not, we must take into account two concepts that are also closely linked to the DDD system:
Strategic design: It could be said that strategic design is the origin of everything. It is a high level vision that defines what the final outcome will be. In this case, for example, this would be using DDD as part of the strategy.
Tactical design: While the strategic design applies to the entire design of the solution, the tactical design is useful to solve problems limited to each part of the solution. It is about defining solutions for specific components of the system. In our case, the use of CQRS is part of the tactical design of some of the system components. CQRS is a design pattern rather than an architecture pattern.
The use of CQRS as part of a system should not belong to its strategic design. It should only be used in the design of some of the components and not become the base of the entire system. If the system is complex enough, using CQRS as the basis for everything may become too complex and some advantages may be lost.
Here are some instances where it may not be a good idea to build a system using CQRS:
User interfaces with simple CRUD operations. If the system you are designing is only an implementation of CRUD operations, CQRS will add excessive complexity to its implementation. At the same time, you won’t benefit from the main advantages of this pattern.
You use simple business logic. If the process you need to implement is simple and each operation has the same number of reads and writes, you probably don’t need to use CQRS. You won’t need to scale read and write operations separately or add unnecessary complexity to the implementation.
If you don’t need to scale the system. Similar to the previous point, if you are sure of the load that your system will have over time, and that the system you are designing doesn’t need to be scaled, you probably don’t need to use CQRS.
This can be very difficult to predict. The needs and usage of a system usually changes over time and, although at the beginning of the project you may not expect a large workload, this may change over time and become an issue. Even so, if you’re sure that you won’t need to scale your system, you should take this into account when deciding to use CQRS or not.
Apply CQRS to the whole system. As mentioned earlier, CQRS doesn’t need to be used in all parts of the system. It is important to define your Bounded Contexts and identify in which of them would benefit most from the use of CQRS.
If your system isn’t divided into small components with a limited and well defined responsibility, it’s not a good idea to use CQRS. The first step should be to divide your system into small and manageable parts. Then consider which of these components would work better using CQRS.
Eventual consistency. One of the main characteristics of CQRS system is that it always has an “eventual consistency” in the data. That is, the information that the query subsystem retrieves may not always be updated with the latest version that has been processed. This is due to the synchronization process that updates the information in the query subsystem repository. When processing the events, it can cause a certain lag between the executed operations and the information retrieved in the queries. If you use CQRS you should be aware of this eventual consistency and, in the case of your business needing to have strong consistency, you should not use CQRS.
If you are considering using CQRS when implementing a new system, I hope this post can help you decide.
Author: Santiago Herranz Fernández, Software Engineer at Intelygenz
For a free assessment, answers to your questions, or to discover how software and AI can be integrated into your business, don’t hesitate to get in touch below:
Get the latest roundup of the most important, interesting and stories from the past week. In your inbox every Saturday by 10am.
Tech Stack: Explaining Software Architectures
Published March 20, 2020
Decade Round-Up: 5 of the Most Relevant A.I. Innovations of the 2010s
Published March 6, 2020
Using Software to Improve Insights Into Student Demographics
Published February 28, 2020