CQS – an easy, yet powerful pattern

CQS – an easy, yet powerful pattern

CQS stands for the command query separation. There’s a chance that you may have not heard about it, but on the other hand the CQRS might ring a bell. Even though these 2 patterns have very much in common, there is a significant difference (definitely a bigger one than the additional “R” character within the CQRS acronym) in how do they apply to the architecture of our system. In this post I’ll focus on the CQS – the older brother of the CQRS – that will help you understand how to design the software that is less error prone.

 

At first, I do encourage you to read the formal definition of the CQS on the Martin Fowler’s blog, in case it’s really the first time you have ever heard about this term. Honestly, it’s quite easy pattern to understand, basically it all boils down to just a two principles: first one about executing an action via command that has side effects, and the second one about fetching the results via query that has no side effects. But let us not be mistaken, simple is powerful (especially here). So what is the CQS really about? Well, there are two things to remember:

  1. The command mutates the state, but does not return a value.
  2. The query returns a value, but does not mutate the state.

So what does it really mean? Let’s take a look at the example below:

As we can see, the method Create() does not return any value. Its only job is to create a new user account (and probably perform some validation first etc.). The important part here is that we are certain that this action has some kind of “side effects” (new user account will be created), so it does mutate the state.
On the other hand, both the GetByEmail() and FindAllByName() functions, do not have any kind of “side effects” (do not mutate the state). These actions (queries) are responsible only for fetching the users from some data storage. It means that we can execute them N number of times, and we will always get the same results.
Having that knowledge, we can redefine the above principles into something like this:

  1. The command has side effects (e.g. creates and saves a new entity) and will be of type void (or Task for the async methods).
  2. The query has no side effects and will be idempotent (always returns the same output e.g. the list of users).

And these are the most important pieces of the CQS pattern. You don’t really have to use the command and query handlers to follow these principles. Surely, they do fit well with this pattern but are not crucial. The important lesson here is to keep in mind that if you try to design the business logic in a way that the read & write operations will be separate from each other, it will help to reduce the number of errors (some unknown behavior/side effects) and also improve the scalability of the application (you could move read & write operations into the separate services, like physically separate not just logically). Anyway, before you try the CQRS (which is a far more advanced pattern) make sure you master the CQS first.

6 Comments CQS – an easy, yet powerful pattern

  1. Pingback: dotnetomaniak.pl

  2. Pingback: I command you (pattern) | Piotr Gankiewicz

  3. Pingback: .NET Core + RabbitMQ = RawRabbit | Piotr Gankiewicz

  4. Pingback: Async HTTP API and service bus | Piotr Gankiewicz

  5. Gemma Black

    For the query side, would you ever use a viewmodel or just plain data objects that feed into the view? …or maybe something else. And thanks for the article. I love the principles of CQS and CQRS and am trying to figure a good way of passing data to my views with a separate model.

    Reply
    1. Piotr Gankiewicz

      Hi Gemma,
      For me, the CQS is all about separating queries and commands. The CQRS, on the other hand, is a sort of sophisticated implementation of the CQS extended with the fast read database (or any other type of storage).
      I’m using the CQRS in some of my recent projects (based mostly on the microservices architecture), and I have a single database for fast reads that stores already flattened objects (e.g. ViewModels or DTOs) that can be directly returned to the consumer – I hope that helps.

      Reply

Leave A Comment

Your email address will not be published. Required fields are marked *