What is CQS/CQRS (Command & Query Separation)?
First, let’s agree that each method of a class can do one or both things:
- It can mutate a private value of the class (hence you tell the object to mutate it, therefore it is also called a “Command”).
- It can return an object/value as a result or additional data (hence you want to query the object to tell you something).
Let’s see some examples (TypeScript):
Don’t worry about the long class, you can instantly skip to the methods explanation right beneath it.
Let’s look at methods by category:
You can see that we ask the object to do something, we command it to mutate and increment its inner value by 1.
The following method is a simple ‘gettter’ of the property innerInteger, we ask the object to tell us things (what is your value?), and not do things.
As the method is a simple ‘getter’ it is a bit hard to understand the concept of query, so I’ve written another method that simply asks the object “are you larger than the other object?”.
Both Command & Query:
The function ‘changeTo’ as its name implies, tells the object to change its value to some other value, but only in case it does not already have that value, and then it returns (it tells us) if the value was indeed changed or not.
So, what about separation? the CQS principle says that we should separate commands from queries, i.e. each method should be or a command that mutates inner data, or a query which returns data and tell us things, but not both.
Why? and if that so, what’s wrong with the ‘changeTo’ method?
CQS principle is all about transparency of what that method do, and about separating methods that mutate the state from the methods that does not. Many reputable authors describe the state as the root of all evil of programming errors, especially Yegor256, a pure object-oriented-paradigm advocate, or how he likes to call it: Elegant-Objects, where he calls CQS as a pattern of “Builders and Manipulators”
Why is mutating state so bad? I wouldn’t say it is bad, most of the times it is even inevitable to not mutate state, but state makes many things unpredictable, state can make two calls to the same method at different occasions to return or do different things, which makes it hard to test, look at the following example:
The same query method ‘isLargerThan’ return two different results because the state is altered, the result could not be changed if the state wasn’t mutated, that is one of the reason that in multi-threaded programs the functional-programming paradigm takes a lead over object-oriented.
So by separating commands from queries, we now have set of methods, called queries that we can call as many times as we like without worry that something might go wrong with the object because something is changed inside.
The problem with ‘changeTo’ method is not about mutating state, as its purpose is more of a command than query, but it lacks transparency, when a programmer sees the method for the first time, he reads the name ‘changeTo’ and get the idea that this method is a command that changes some value, but how could he know that it returns anything? and if it does return something, what does it return and why? the method name does not make it clear at first glance all the things that the method does, in fact, it does two things, mutating and returning its result, which people might be thinking that it could be a violation of the Single-Responsibility principle (SRP), but it can be confusing as the SRP talks about separating different axes of change and not different logic, but the same idea applies here, we want to separate the methods that mutates the state, and those who don’t.
In pure object-oriented style, where everything is an object, we can perhaps introduce a new ‘ChangeRequest’ class which will store the result if the value was indeed changed and also execute the request.
Notice that this type is more of declarative then imperative as we don’t immediately change the value at ‘changeTo’ method, instead we delegates the work to some other request class that can be executed when we see fits, which handles everything about the ChangeRequest such as executing it and storing its result, ‘changeTo’ now becomes a query (or a builder by Yegor) which returns an object of type ChangeRequest that has methods of ‘execute’ which is a command and ‘isChanged’ as query.
Some people would say that if these 4 lines of code above were written inside a method, they would violate the Law of Demeter (LoD) as ‘req’ of type ChangeRequest is created by another object ‘number’ of type ‘MyNumber’ that probably was passed to the method as an argument or stored as a private field inside the class, and by executing ‘req.execute()’ the violation is inevitable.
Someone once asked me, if CQS principle is so important, then why many people still don’t use it? take for example Java’s Set data structure with the method ‘add’:
In Java, the ‘add’ method of Set is a command and also a query, it adds a new item to its internal data structure (hence mutating its state) and also returns boolean value true/false if the item was already present in the set or not, as was said before, it lacks transparency, a programmer reading these lines would have to consult with the documentation to know what ‘add’ returns, because the name of the method does not imply anything that should be returned by it, I’m just adding a new string “Neyney” to the set right? what should I expect in return?
The simple answer is that CQS, like any other principles, is not a hard rule that should be applied everywhere, it always comes with a cost of complexity, like seen in the example of the method ‘changeTo’ we had to introduce a whole new class and methods to follow CQS along with violation of Law of Demeter, keeping the method as it is without changes will be simpler to use, shorter to use and more (arguably) readable code when using the method as a simple operation as adding a new item to set wouldn’t take full 3 lines of code to accomplish.
In short, commands can be seen as the inputs to the object as they alter its state, and queries can be seen as the outputs of the object as they tell us about the state, a method that does both, ties its input and output together which can sometimes lead to harder testability and lack of transparency.
- https://martinfowler.com/bliki/CommandQuerySeparation.html | Martin Fowler, CommandQuerySepartion.
- https://martinfowler.com/bliki/CQRS.html | Martin Fowler, CQRS (Command-Query responsibility segregation).
- https://www.yegor256.com/2018/08/22/builders-and-manipulators.html | Yegor, Builders and Manipulators.
- https://www.elegantobjects.org/ | Yegor, Elegant objects.
- https://www.yegor256.com/2014/06/09/objects-should-be-immutable.html | Yegor, objects should be immutable.
- https://blog.cleancoder.com/ | Robert C. Martin, The Clean Coder blog.
- https://en.wikipedia.org/wiki/Law_of_Demeter | Law of Demeter.