Loïc Faugeron Technical Blog

Command/Query Responsibility Segregation 25/08/2015

TL;DR: CQRS is about not mixing "read" and "write" logic. You can use patterns like a Repostiory / Search Engine and Command Bus to help you achieve this.

The Single Responsibility Principle (SRP) has many applications: we can find it in the Unix philosophy ("do one thing and do it well") and usually refactoring is all about identifying responsibilities and extracting them in their own classes.

Command/Query Responsibility Segregation (CQRS) can be viewed as a part of it.

In this article, we'll explore the pros and cons of CQRS and we'll see some ways to implement it.

Messages

We usually communicate with our application by giving it an input which can be viewed as a "message". Messages can be classified in 3 different types:

Note: For more information, have a look at Messaging Flavours by Mathias Verraes.

The CQRS principle states that Imperative messages should not be mixed with Interrogatory ones.

Note: Here's an interresting article about validating those messages.

Asynchronous use case

Let's take the A/B testing example: we'd like to know which setting will attract more visits on a given page. To do so when a user visits the page, we send a request to an API with some helpful information.

On receiving the request, the API can simply push a message to a Messaging Queue (e.g. RabbitMQ). This request was an Informative message.

Note: To learn more about RabbitMQ, have a look at this article and those slides.

Eventually, the Messaging Queue will call a consumer and give it the message: now the consumer must register the information somewhere. This message is an Imperative one.

Later on, we can display the statistic on a dashboard. This time, we're dealing with an interrogatory message.

As we can see, the CQRS principle is applied here. It is really useful whith asynchronous use cases.

Synchonous use case

Another example would be member registration: a new member submits a registration form. If it is valid, they're told to check their email: a confirmation token has been sent to them.

Behind the scene, our application receives the request: it is an Imperative message so we create a token and save the information somewhere. Once done the application can send a "Member registered" event, which will trigger a listener that will send the email.

Note: the registration logic can be decoupled from the email logic: we can first have a service that registers members and when done sends a "Member registered" event. Then a listener could call our email service.

Once again, we've applied the CQRS principle, but in a synchronous use case. If later on our application gets successful, we'll might want to make those process asynchronous and it will be easy to do so.

Imperative messages expecting return value

Our final example will be about an API that allows scientists to report a new species. They need to send a POST Request to the endpoint, which in turn will return a response containing the created resource.

The issue here is that we're going to mix an Imperative message (report a new species) and an Interrogatory message (get the newly reported species).

CQRS cannot be applied "fully" everywhere, but we can try the following compromises:

Note: for the second solution, we need to create our own UUID, instead of relying on the database to generate the IDs.

Handling Imperative Messages

The Command Bus pattern is really helpful to handle Imperative Messages. It's composed of 3 objects:

The Command would be constructed in an entry point (Controller, Command, EventListener), with parameters extracted from the input (Request, Input, Event) and then given to the CommandBus.

The CommandBus is usually a Middleware:

Note: To learn more about this pattern, have a look at the following articles:

Handling Interrogatory Messages

There's actually many options to handle Interrogatory messages.

Repository

The Repository design pattern introduces a class that acts like a collection, but behind the scene relies on a Gateway to actually retrieve data (could be from a file, a database, a remote endpoint etc) and on a Factory to format the returned value.

Usually "find" methods are added to the repository with a name describing the expected criterias.

Note: Here's a list of nice articles about this parttern:

Criteria

Sometimes the repositories will grow bigger and bigger. The alternative solution would be to build a Criteria object and pass it to a service.

Here's some of these solutions:

Personally I've been experimenting with a Proof Of Concept (POC): SearchEngine. I still need more experimentations to start advising on this subject, so if you want to share your experience you'd be welome to post a comment :) .

Conclusion

CQRS helps you to decouple your code (from itself and from third party libraries) even if, like every principles, it cannot be applied everywhere.

To help you apply it, you can use Command Bus and Repositories / SearchEngine.

Note: Here's a list of interresting articles about CQRS: