cult3

What is Command Query Responsibility Segregation (CQRS)?

Jan 14, 2015

Table of contents:

  1. Two problems in application development
  2. What is Command Query Responsibility Segregation?
  3. Using two separate data stores
  4. How is Command Query Responsibility Segregation implemented?
  5. When should you use Command Query Responsibility Segregation?
  6. Conclusion

One of the beautiful things about Domain Driven Design is the fact that there isn’t one recommend style of architecture that must be used in every project. All applications are different and so trying to impose an incorrect architectural style would be a disaster.

In Domain-driven Design: Tackling Complexity in the Heart of Software it is recommended that you split your application into layers of responsibility. Broadly speaking, this would mean you would have a Domain Layer, an Application Layer and an Infrastructure Layer.

A couple of weeks ago we looked at Hexagonal Architecture and the idea of using Ports and Adapters to create an agnostic layer between our Domain Model and the outside world.

Last week we looked at Service Oriented Architecture, which provides distinct units of functionality as agonistic network services provided via an interface.

This week I want to look at Command Query Responsibility Segregation (CQRS), how this particular architectural pattern works, the benefits and drawbacks and when you should choose it for your projects.

Two problems in application development

Architectural patterns such as Command Query Responsibility Segregation are usually perfect for a limited number of problems, and wildly inappropriate for others. This distinction is even more polarised for Command Query Responsibility Segregation because of the complexity in its implementation.

I think there are two main problems Command Query Responsibility Segregation aims to solve.

Cutting across Aggregates

In most web applications, you have objects that hold responsibility and Domain logic around important concepts of the business.

For example in an Ecommerce application, you might have an Order Entity and a OrderRepository. The OrderRepository would be responsible for finding Order objects from the database as well as adding or updating new or existing Order objects.

In this example you could imagine that Order would be an Aggregate (What are Aggregates in Domain Driven Design?), and we would probably have Repositories for the other main Aggregates of the application.

Theoretically this is a fairly elegant situation and so we would have simple and maintainable code to work with.

However, in the real world, life is not always this simple.

In certain types of Applications you will be required to display data from multiple different Aggregates as part of a single User Interface. This presents a problem because it means we need to cut across Repositories to pull the data we need.

This means we either need to blur the lines of the Repositories, or force the User Interface to conform to the restrictions of our architecture. Domain Driven Design is all about solving the problems of the business, and so limiting the possibilities of the User Interface is out of the question.

There are a couple of ways to solve this problem, but none of them are ideal.

Firstly you could use multiple Repositories to collect the data and then assemble it together. This would be undesirable because it would force you to pull data from the database that isn’t required and you would have to then massage the data into the correct format for the User Interface.

Alternatively you could define a finder method on one of the Repositories that holds the responsibility for querying for all of the data. Again this would be undesirable because the lines of responsibility of the Repository would be blurred.

Imbalanced application responsibilities

Another appropriate situation for using Command Query Responsibility Segregation is when the application you are building has an imbalance in responsibility.

For example, imagine your application is has a very high number of reads, but a very small number of writes, or perhaps your application is required to do very intensive processing on the data that it accepts.

Command Query Responsibility Segregation allows you to split the two sides of the application into separate models so you can optimise them in isolation.

This prevents you from negatively effecting one side of the application to meet the requirements of the other side.

What is Command Query Responsibility Segregation?

Command Query Responsibility Segregation (CQRS) is an architectural pattern that separates reading and writing into two different models.

This means that every method should either be a Command that performs an action or a Query that returns data. A Command cannot return data and a Query cannot change the data.

So thinking back to the Ecommerce example from earlier, we would need to create two separate models for reading and writing. We would have an Order Aggregate that would have only Command methods and a OrderRepository that could only add and update Order objects. This would be the write model.

In order to read data from the database we would need a separate read model. For example, this might be a dedicated Repository that is specifically tuned to return the correct data for an appropriate view.

By splitting the application into dedicated read and write models, you move the responsibility into dedicated objects. The write model does not need to be concerned with returning data and the read model can be specifically written to return the correct data to satisfy the application’s requirements.

Using two separate data stores

The main principle behind CQRS is that you use two different models for reading and writing. However, the actual implementation of this idea can be handled in a number of different ways.

Firstly you might use two different models that talk to the same database. When a user issues a Command, the write model will update the database and then the read model will query the database to present the data to the User Interface. This is good solution for applications that require synchronous processing and immediate results.

However for other types of applications, it might be desirable to use two different data stores.

Rather than writing and reading from the same database, the write model will send commands to one database, and then the data will asynchronously update the read database.

This approach has a number of benefits.

Firstly, this allows you to store the data in the read database as denormalised data. This has the advantage of allowing you to write more efficient queries, but also store data that makes more sense as to how it should be displayed in your application.

Secondly, it allows you to scale the two different sides of your application separately. If you have a very high number of reads, and a low number of writes, you can scale the query side of the application without worrying too much about the write side. This would be advantageous if your application is required to do intensive reporting queries.

How is Command Query Responsibility Segregation implemented?

When implementing Command Query Responsibility Segregation you will typically see many of the same patterns. The following are four of the common aspects of the implementation of Command Query Responsibility Segregation.

Task-Based User Interface

One of the big benefits of using Command Query Responsibility Segregation is that it is more focused on the intent of the user.

In typical CRUD type applications, the user interface is often just a thin layer over the database that allows the user to create, read, update and delete.

By forcing the interface to conform to these four basic methods, you are losing the intent of the user. An application shouldn’t be just a thin layer over a database, it should help the user achieve a goal.

Because Command Query Responsibility Segregation is not focused around CRUD it can allow you to write a task based UI that cuts across the application to offer a rich, intention based interface to the user.

This means instead of an awkward user interface that attempts to conform to the architecture of the application, a CQRS user interface will be finely tuned to solve the needs of the user.

Command Processing

In Command Query Responsibility Segregation applications, the write model and the read model are separate and so processing requests requires a slightly different mental model.

For example, a common pattern in web applications when creating a new resource is to redirect to display that resource on success.

However, because the read and write models of a Command Query Responsibility Segregation application are separate, when you create a new resource, you aren’t returned the id of the newly created resource.

Command Query Responsibility Segregation applications typically use a Command Bus for dealing with this flow. We looked at creating a Command Bus in a previous tutorial, Creating and Using a Command Bus.

A Command Bus should never return a value because that would break the separation between the read and write models. A write action should never return a result.

So the answer to the predicament of not being able to redirect on success is usually simpler than you would expect. If you really need that kind of functionality, you probably shouldn’t be using Command Query Responsibility Segregation for that part of your application. In fact, you probably shouldn’t be using CQRS for your entire application anyway.

Synchronous or Asynchronous

As I mentioned above, with Command Query Responsibility Segregation you will often see examples of Synchronous or Asynchronous processing.

Synchronous process allows you to return a response immediately to the user. This is important when the user interface demands an instant result.

However, for certain types of applications, a response is not always required immediately.

For example, if the data has to go through a complex or intensive period of processing, Command Query Responsibility Segregation can be the answer to your problems. CQRS allows you to write your data to one source and then have it asynchronously processed and then transferred to the read database.

This process is known as Eventual Consistency. If your application does not require immediate results, than using Eventual Consistency can remove a lot of headaches.

Domain Events

And finally, Domain Events are usually very important to Command Query Responsibility Segregation applications. In the example above using Asynchronous processing, it would be Domain Events that initiate that process.

Domain Events listen for certain events during the execution of an application to trigger other actions. This allows you to decouple the consequence of an action with the action itself.

We’ve previously covered Domain Events in the articles, Implementing Domain Events and Creating your own Domain Event Dispatcher.

When should you use Command Query Responsibility Segregation?

So as you can see, Command Query Responsibility Segregation isn’t for the faint of heart. Using CQRS would be widely inappropriate for the majority of all web applications.

Adding unnecessarily complexity to a web application can be the kiss of death. You should always aim to write the simplest solution rather than go nuts for architecture just for the sake of it.

However, for certain types of web applications, I’m sure Command Query Responsibility Segregation would be the answer you are looking for.

Applications that are appropriate for CQRS will typically have many of the same characteristics.

For example, they will require a task-based UI, complex data processing, an imbalance in reads and writes, and eventual consistency would not be a problem.

Unless you face these characteristics, you shouldn’t be using CQRS.

Conclusion

Command Query Responsibility Segregation is an important architectural pattern that you should be aware of as a developer. It has many advantages to some of the most difficult problems when building complex and large scale applications.

However, this type of architecture is especially tuned to solve a very specific subset of problems. This add considerable complexity to your application.

As with most patterns in software development, CQRS is only really applicable for certain situations. Adding architectural complexity just for the sake of it would probably be a bad idea.

However, with that being said. It’s always good to know about different approaches and common methods to solve difficult problems. One day you might face a situation where CQRS would be the perfection solution.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.