CQRS is an architectural pattern that prescribes a strict split within an application and suggests to isolate the command and query components from one another. Axon Platform helps by providing the necessary building blocks and infrastructure to build and run these components, and dispatch messages (commands, events and queries) to the right destination within an application.
What is CQRS - Command-Query Responsibility Segregation
Command-Query Responsibility Segregation, CQRS for short, is an architectural pattern that prescribes a strict split within an application. A split between the part which deals with processing operations and the part which deals with answering questions. “Processing operations”, the “expressions of intent” targeted towards an application, is what is referred to as the Command side. “Answering questions”, the “request for information” about an applications state, is what is defined as the Query side of an application. CQRS thus suggests to isolate the command and query components from one another.
Segregating these concerns introduces some consequences when writing software, but more importantly it introduces several benefits. First and foremost, it gives a single purpose to a component, increasing the focus on the problem at hand. The component is thus optimized for either dealing with commands or queries. This focus is highly beneficial when developing software.
Secondly, the segregation allows for dedicated deployments of the command and query side.
Non-functional requirements like differing scaling requirements can thus be achieved. Does the application have high demands for handling queries? Simply scale up the number of query instances of your application, without imposing any changes to the command handling part.
The same obviously holds if large amounts of state-changes should be processable; just introduce more command instances.
Benefits alongside the non-functional requirements reach a little further than just scaling. Different accessibility approached and data persistence options can be selected per side of the application. A different choice of database for the Command side compared to the Query side has now become trivial as they no longer rely on one another. Requirements for a more efficient way of storing the application state, to optimize for answering queries, is now a design option for an application.
The Command Model is tasked with handling the expressions of intent which an application might have. Such an expression of intent, the command, in general is a business operation that ideally maps to specific task that can be performed. Upon receiving the command, the model will decide whether that task can be executed at that point in time. The decisions making process when handling the command is driven by business logic within the domain the application resides in.
These commands can be simple state changes within the application or potentially trigger a multitude of side effects. To decide on this outcome, the Command Model will require some state. The state should by no means encompass all the data flowing through the application. The only information which is necessary in the Command Model, is the information which is required to make the decisions; no more, no less. This focus on dealing with commands keeps the model concise, both in operations it should be able to do and state it should keep for that task.
The Query Model, also referred to as “Projection” or “View Model” will not deal with any expressions of intent to adjust state or perform some operation. Its sole purpose is to deal with requests for information. The requests for information, the queries, an application should be able to handle can come in very different formats, ranging from lookups based on an identifier to full text searches on large sets of data. The query side of an application thus needs to support different approaches to retrieving the applications state.
Due to the decoupling of the command and query side with CQRS, we can quite easily any storage format for the Query Model without influencing the Command Model’s approach to storing its state to make decisions. It also allows to implement several storages approaches tailored towards the type of query which needs to be dealt with.
Is the query performed to fill JSON-based web page through a specific identifier? Use a denormalized view in your Query Model, which stores that page as JSON alongside the identifier in the NoSQL solution of your choosing. Are there requirements that the application should also provide a search box for users to query several documents based on keywords? Introduce a second Query Model using a search engine to support such request.
The segregation allows to optimize for the query for the exact use case to be as performant, flexible or storage efficient as possible. It will introduce data duplication and where needed data denormalization. This is however very desirable, as your model will focus on what it should return as best as it can, making the overall application more concise and reliable.
Even though CQRS breaks apart the Command and Query side into dedicated components, they are still part of the same application. As such they need to synchronize. As the Command Model is in charge of handling the commands which incur states changes, it will notify the application that such a decision has been made. There are several ways to achieve this, with for example a shared data source between both models or through stored procedures. Using events as notifiers for the synchronization requirement is however the suggested solution.
When levaring this Event Driven Architecture, the Command Model would thus publish an event upon (successfully) handling a command. The event will then be handled by the Query Model(s) to update it’s state accordingly. Following this pattern for synchronization also allows us to update the Command Model based on the events it publishes itself (see Event Sourcing).
All the above can be combined into the following diagram:
Using CQRS within your software is something AxonIQ strongly believes in. Axon Framework helps you tremendously in that respect, providing the necessary building blocks and infrastructure to create command models and dispatch all the command, event and query messages to the right destination within your application. Doing so allows a focus on business functionality first, without the need to think how to tie everything together.
The idea to use messages to describe commands, events and queries, respectively used to deal with the Command Model, synchronize changes and to retrieve data from the Query Model, is an important pillar for enabling microservices. Leveraging CQRS together with messages allows a monolith first approach to your application. This solution imposes internal segregation, but does no prescribe the necessity for the software to consist of separate pieces from the start. This idea ties in neatly with creating business functionality first and implementing some of the non-functional requirements later.
Following this segregation opens up the possibility to pull apart an application into dedicated command and query services at a later point in time, albeit for scaling out, team structure or other non-functionals. It thus allows evolving an application towards microservices as soon as its necessary.
Sign up for email notifications
by submitting you agree to receive occasional emails