CQRS
(Command-Query Responsibility Segregation)
A software pattern that separates command (or update) and query (or read) operations in applications.
Watch webinar: CQRS and Event SourcingIntroduction
CQRS is a software architectural pattern acronym, related to an earlier-coined term, CQS.
This page will explain CQRS and CQS. How one is derived from the other, the benefits of CQRS and its core principles, as well as some misconceptions around the pattern.
What does CQRS stand for?
CQRS stands for Command Query Responsibility Segregation. It is a software architectural pattern based on the segregation of the responsibilities of the commands and queries in a system.
What is CQRS?
Command Query Responsibility Segregation (CQRS) is the segregation of the responsibilities of the commands and queries in a system. That means that we're slicing our application logic vertically. In addition to that, we're segregating state mutation (command handling) from the data retrieval (query handling).
CQRS was defined by Greg Young:
Command and Query Responsibility Segregation uses the same definition of Commands and Queries that Meyer used and maintains the viewpoint that they should be pure. The fundamental difference is that in CQRS objects are split into two objects, one containing the Commands one containing the Queries.
"Objects" in the original definition are not connected to the storage, but to the handlers. We're creating different pipelines for different business behaviors, not separate storage.
What is CQS? And how does it relate to CQRS?
CQS is a design pattern, and the acronym stands for Command Query Separation. CQS is the core concept that defines two types of operations handled in a system: a command that executes a task, a query that returns information, and there should never be one function that does both of these jobs.
The term was created by Bertrand Meyer in his Book ‘Object-oriented Software Construction’ (1988, Prentice Hall). He created it as part of his work on the Eiffel programming language.
CQRS takes the defining principle of CQS and extends it to specific objects within a system, one retrieving data and one modifying data. CQRS is the broader architectural pattern, and CQS is the general principle of behaviour.
Benefits of CQRS
Building your architecture using CQRS principles will offer many advantages.
-
Clear boundaries between the system behaviour
It provides specific guidance on structuring the application in relation to behaviour.
-
Closer to business logic
The code and architecture are segregated by their business operations, making it easier to focus on the business case.
-
Loose coupling
The logic is cohesive and less interrelated, making it easier to create a modular, maintainable applications.
-
Reduced cognitive load
Due to the vertical split, related code is kept together. To modify existing code or create new code, you don't need to understand the whole architecture and business logic. It's easier to focus on a specific task.
-
Easier scaling, optimisations and architectural changes
As our code is kept in silos, it's easier to fine-tune only one pipeline, leaving the rest untouched. It's easier to focus on the precise optimisations in the places that are business-critical.
-
Predictability
Due to the segregation, you have the general rules for operations behaviour. You won't be surprised by the query changing the application state; keeping the separation between the write and read logic reduces the chance of ending up with spaghetti code.
Core Principles
The core principle of CQRS is the separation of commands and queries and what they do. They perform fundamentally different roles within a system, and separating them means that each can be optimised as needed, which can be hugely beneficial for distributed systems.
Alexey Zimarev has defined how commands and queries are different:
On a high level, CQRS states the fact that operations that trigger state transitions should be described as commands, and any data retrieval that goes beyond the need of the command execution, should be named a query. Because the operational requirements for executing commands and queries are very often different, developers should consider using different persistence techniques for handling commands and queries, therefore segregating them.
Commands, queries, and their relations to write and read models are defined below.
Commands
A command is an instruction, a directive to perform a specific task. It is an intention to change something. Bertrand Meyer wrote:
A command (procedure) does something but does not return a result.
A command should convey the intent of the user. As explained by Alexey Zimarev here, handling a command should result in one transaction on one aggregate; basically, each command should clearly state one well-defined change.
The commands make up the write model, and the write model should be as close as possible to the business processes.
Queries
A query is a request for information. Back to Bertrand Meyer:
A query (function or attribute) returns a result but does not change the state.
It is an intention to get data, or the status of data, from a specific place. Nothing in the data should be changed by the request. As queries do not change anything, they don't need to involve the Domain Model.
The queries make up the read model. The read model should be derived from the write model. It also doesn't have to be permanent: new read models can be introduced into the system without impacting the existing ones. Read models can be deleted and recreated without losing the business logic or information, as this is stored in the write model.
CQRS and Event Sourcing
CQRS was introduced by Greg Young in 2010 at roughly the same time as Event Sourcing. He described it as a ‘stepping stone towards Event Sourcing’.
An event-sourced system does not store the state of the domain object explicitly, it stores the changes to that state. In an event-sourced system, the state is stored as a series of events. These events are all business operations. Read models are built from events and are usually kept in a separate database tuned to query needs.
Event Sourcing goes well with CQRS, as events are the results of the business operations. That makes it a great partner for CQRS, as CQRS by its nature divides the system by the business operations.
It’s important to understand Event Sourcing and CQRS do not rely on each other; you can have an event-sourced system without CQRS and you can use CQRS on without Event Sourcing. It’s just that the two work well together.
CQRS and DDD
Domain Driven Design (DDD) is a method for optimizing a team’s understanding of a problem space, and how to work in that space. It’s about having a ubiquitous language that is used by business users and the development team. This unification of language can be extremely useful when translating the problem concept into functioning software.
CQRS and DDD are separate, orthogonal, concepts. You do not need to use CQRS to use DDD, or vice versa. When they are used together, DDD can provide a bounded context, derived from conversations from the business, and CQRS can define how the work is moved through the system. DDD is aligned in principle with CQRS, but definitely not interdependent.
CQRS misconceptions
"Commands and queries need to be run on separate databases, and everything must be stored in separate databases."
This isn’t necessarily true; only the behaviours and responsibilities for both should be separated. This can be within the code, within the structure of the database, or if needed, different databases. It is not a requirement that they are in separate databases.
Expanding on this, CQRS doesn’t even have to use a database: It could be run off an Excel spreadsheet, or anything else containing data. Oskar Dudycz explained this in an article:
Nothing then stops you from using a relational database, even the same table for reading and writing. If you prefer, you can continue to use an ORM. Nothing prevents the command from adding/modifying records and query retrieving data from the same table. As long as we keep them separated in our architecture.
CQRS is applicable to the behaviour of a system, not about where data should be stored. Remembering that CQRS refers to behaviour, and not storage, is key to creating efficient CQRS applications.
"It can only be used with DDD, and you need both for Event Sourcing"
There's also a misconception that CQRS must be used with DDD, and both are needed for Event Sourcing. These are not true; you can apply CQRS without knowing much about DDD or using its principles, and it's possible to create an event-sourced system without CQRS or DDD. The concepts work well together, but they are not inter-dependent.
"CQRS creates eventual consistency problems"
Separating commands and queries and handling them differently can make a system eventually consistent. There's a misconception that eventually consistent systems are more inaccurate due to the time delays involved, and that with the separation of commands and queries in CQRS, there must be delays and therefore eventual consistency problems.
The truth is many kinds of systems will have eventual consistency problems; wherever there is a delay between an input being received, being recorded, and being called out again. These delays are in the order of milliseconds, within the tolerance of most systems. When implementing CQRS, eventual consistency is no more of a concern than it is when using other patterns.
"CQRS systems will always need messaging queues"
Not necessarily. Message queues such as RabbitMQ and Kafka allow you to send messages between the write model and the read model, depending on the circumstances. If your model is quite simple and starts with different database views (or even the previously mentioned Excel spreadsheet), message queues are not needed. Building your system with CQRS in mind will allow you to have the different kinds of databases interacting with each other, for example (to use Oskar's description), you could use a relational database on the write model and a document database on the read model. Messaging queues would be useful in this situation to keep the read models updated when and if the write model changes. If possible, it's best to use the in-built storage mechanism, such as subscriptions for event stores or change detection capture for relational databases, as it will make your solution more straightforward, but it depends on what is needed in that specific business context.