What is Command Query Separation?
The Command Query Separation (CQS) concept is a way to structure your code and methods. The idea is that a method may either be a Command or a Query but not both. It was coined by Bertram Meyer in his book ”Object Oriented Software Construction” from 1994.
What identifies a Command method?
A Command is a method that typically alters the state of the program or system, but does not return any data. One example is adding a new item to an inventory:
public class Inventory { // Command to add an Item to the inventory public void AddItem(Item item) { ... } }
A Command method may call Query methods to request information about the current state if needed.
What identifies a Query method?
A Query is a method that returns information about current state of (a part of) the system. It may in no way alter the state of the system. Hence, a Query method may not call any Command methods. One example of a Query method is requesting information about an item in an inventory:
public class Inventory { public Item Find(Query q) { // Look in the inventory for an Item matching the query ... return item; } }
What are the benefits of CQS?
The really valuable benefit is that it makes it really easy to see which methods that modifies the state of the system and which don’t. Those methods that don’t modify the system can be re-arranged and called whenever needed, and those that do modify the state of the system must be handled more carefully. This makes it easier to work with the code and understand what happens in the system for different scenarios.
One of the worst practices I have seen is when the get section of a property modifies the state of the system:
// Never ever write code like this! private int _x; public int X { get => ++_x; set => _x = value; }
When would you not use CQS?
There are some scenarios when CQS doesn’t really fit. Martin Fowler mentions the Pop method on a Stack as an example. Pop usually removes the top element of the stack and returns it, hence both modifying the state and returning a value. Most of the time it is however a good idea to apply CQS.
In the Wikipedia article on CQS it is stated that CQS can make it harder to implement multi-threaded software. As an example it shows a method that increments and returns a value:
private readonly object _lock = new object(); private int _x; public int IncrementAndGetValue() { lock (_lock) { _x++; return _x; } }
which, when adhering to CQS would need to be separated into two different methods, one to increment x and one for returning it’s value:
private int _x; public void Increment() { _x++; } public int GetValue() { return _x; }
With this, the locking has to be done everywhere Increment and GetValue is called instead of locally in IncrementAndGetValue. However, I do not see this as a real issue since it is often better avoid locks in low level methods in order to avoid the overhead in all cases where locking isn’t needed.
My suggestion is that you try to use CQS as often as possible. But when cases presents itself where breaking CQS is the most intuitive, like Pop on a Stack, or when enforcing CQS clearly makes the code more complex, it is okay to break the rule.