The Command Query Separation Principle

The other day I was making some additions to some legacy code that produces website order extracts which are sent to a third party system. I'd created an order in the test database and then wanted to step through a particular method that collects the data and creates an XML document from it. As I began to step through the code, I had to pause and wonder if this seemingly innocuous method would, over the course of retrieving the data and creating the extract file, also perhaps update the data. Which leads me to this post.

The Command Query Separation principle (CQS for short) is a very simple one, but it's also very useful. In short, it states that any method that updates data or modifies state (a command) should not return a result, and any method that returns a result should not update data or modify state. This principle was introduced by Bertrand Meyer in his book "Object Oriented Software Construction".

I find this to be a useful and worthwhile principal to follow. If I know that any of the methods I write that return results won't be updating data or making any changes, then I can more easily use them in other places or call them as needed -- such as in the example above. Likewise, my methods that modify data or state do just that, and nothing else.

I do make one exception to the "commands do not return a value" rule, and that is allowing my command methods to return a boolean indicating success, or in the case of something that, say, inserts a record into a database, returning the ID of the newly created record. In the latter example, to not return a value would require a separate method call to determine the ID of the newly created record, which seems redundant and wasteful if the command method can just return it. But the point is, when following CQS, a method to create a new record would not return a set of data, nor would a method that returns a set of data be making changes to it. Simple principles like CQS can help prevent problems going forward and lead to code that is easier to maintain.

Comments

Popular posts from this blog

A Generic Method Using HttpClient to Make a Synchronous Get Request

The Cause and Solution for the "System.Runtime.Serialization.InvalidDataContractException: Type 'System.Threading.Tasks.Task`1[YourTypeHere]' cannot be serialized." Exception

How To Mock Out Child Components In Unit Tests of Angular 2 Code