Recently, I was reading about some basic encapsulation concepts and I
came across command query separation. So this week I will be talking
about what command query separation is and how it is useful.
According to CQS, any operations in the system should be either command or query but not both.
Command: Any operation that has observable side effect on the system.
Query: Any operation that returns data and does not mutate observable state.
For example, in one of your class, you have
This is saving Employee name into the system. Note the return type void. So this is changing the system state and returning nothing. So it's a command.
Another example, suppose you have
This should return the Employee name from the system and should not change the state of the system in any way. Note the return type is string (not void). So it should be query operation. The query operation should be idempotent i.e. no matter how many times you invoke a query, it should return the same response for a given system state.
Similarly, if you have some Save method like this:
The Save method here is returning a string as well as changing the state of the system. This is against the command query separation principle. Any operation can either return something or change the system state but not both.
By looking at the method signature, we don't know what the string return is. Whether the string returns the Employee name or error message or employeeId casted as string or something else. The consumer of the method will have to look into the method definition to find this out. Imagine if it's a complicated method. So now the consumer will have to either go through all of it or test it by passing different types of values or read through the whole documentation, if any. Any of these is not very favorable and makes us feel that the code sucks.
Having clear separation makes our code more readable, more intuitive and easy to follow. Furthermore, it helps in the maintainability of the code as well. When reading the system state, the consumer should be carefree that he/she is not changing the system state in any way.
As everything is life, the answer to when to use this principle is: "it depends". This is a generic principle to keep in mind when writing code. Nothing prevents you from disobeying the principle but if it can be followed, we should adhere to it.
However, we might have some exceptions where we can't follow the principle verbatim. For example, if you have an email system, where reading an email marks the email as Read. So here the Query operation could be changing the system state and marking the email as Read. So personally I would prefer to follow the principle when I can but I should be ready to break it when needed.
For future updates to my weekly blog, please subscribe to my blog via the "Subscribe By Email" feature at the right.
Command Query Separation (CQS)
The term Command Query Separation was introduced by Bertrand Meyer in his book on object oriented design. The command query separation pattern is not only limited to object oriented design but can also be applied to functional programming or anywhere else.According to CQS, any operations in the system should be either command or query but not both.
Command: Any operation that has observable side effect on the system.
Query: Any operation that returns data and does not mutate observable state.
For example, in one of your class, you have
public void SaveName(int employeeId, string name)
This is saving Employee name into the system. Note the return type void. So this is changing the system state and returning nothing. So it's a command.
Another example, suppose you have
public string GetEmployeeName(int employeeId)
This should return the Employee name from the system and should not change the state of the system in any way. Note the return type is string (not void). So it should be query operation. The query operation should be idempotent i.e. no matter how many times you invoke a query, it should return the same response for a given system state.
Why Useful
This makes the code easier to read and helps us in separating the concerns. Imagine if you have some Get method which also changes the system state. The consumer of your code might get different response on calling the same GET operation. Such a system is non-intuitive and prone to errors and difficult to maintain.Similarly, if you have some Save method like this:
public string SaveName(int employeeId, string name)
The Save method here is returning a string as well as changing the state of the system. This is against the command query separation principle. Any operation can either return something or change the system state but not both.
By looking at the method signature, we don't know what the string return is. Whether the string returns the Employee name or error message or employeeId casted as string or something else. The consumer of the method will have to look into the method definition to find this out. Imagine if it's a complicated method. So now the consumer will have to either go through all of it or test it by passing different types of values or read through the whole documentation, if any. Any of these is not very favorable and makes us feel that the code sucks.
Having clear separation makes our code more readable, more intuitive and easy to follow. Furthermore, it helps in the maintainability of the code as well. When reading the system state, the consumer should be carefree that he/she is not changing the system state in any way.
Conclusion
CQS gives you a good foundation on which you can build good quality software.As everything is life, the answer to when to use this principle is: "it depends". This is a generic principle to keep in mind when writing code. Nothing prevents you from disobeying the principle but if it can be followed, we should adhere to it.
However, we might have some exceptions where we can't follow the principle verbatim. For example, if you have an email system, where reading an email marks the email as Read. So here the Query operation could be changing the system state and marking the email as Read. So personally I would prefer to follow the principle when I can but I should be ready to break it when needed.
For future updates to my weekly blog, please subscribe to my blog via the "Subscribe By Email" feature at the right.
No comments:
Post a Comment