Tuesday, 12 December 2006

Separating Command and Query

Separating command and query is an idea that Betrand Meyer came up with. The general idea is that a method should either be for changing the state of an object or querying that object about its state. eg

widget.Add( 12 ); // command

x = widget.Sum(); // query

Calling sum won't change the state of widget. In fact it is referentially transparent, that is, the call to sum can be replaced with whatever the result of sum is without changing the behaviour of the software. ie


x = 12;

Which just means calling Sum has no side effects.

On the other hand, the command Add" can do whatever it likes to the object. There is no result from the add that represents the changed state of widget.

So why is this a good thing? It helps in separating your code into simple methods that are responsible for just one thing. This often simplifies code. One of the mistakes I have seen people make is that if you have some action that returns a value (mixing command and query). eg

int count = widget.Add(); // returns the number of items in widget

And you use this method in one place, everything seems fine. Sometime later you find you really need to know count somewhere else. But the only way to find out the the count is by adding something. Nuts. So you may end up storing the value of count somewhere for later retrieval but then this starts complicating another object with the details of widget, and worse, count may be wrong by the time you use it, or, even worse yet, you may end up doing a hack that Adds something to get the count then immediately removes it again. Where as what you really need to do is separate the command and query and simply ask the widget for its count whenever you need it. This is a bit of a simplified example and generally you fall into this trap when the objects and methods semantics are not so clear. In fact sometimes renaming a method can be all that's needed to show this confusion.

Of course, there are many examples you could come up with as to why you may not want to separate command and query. That's fine. As long as you know you're doing it. Most of the problems come when you don't realise your doing it. It's just one thinking tool that helps you evaluate code and potentially help you name a problem.

One nice thing you can do if you do with commands is return this/self as the result. This then allows you to do command chaining eg.


widget.Add(1).Add(2).Add(3);


For some, this whole command query thing may seem all too obvious and trivial, but I wanted to blog on it since I have seen people getting their code in a mess because they didn't make the clear distinction between command and query.

No comments: