I’m not sure whether I’m using the accepted terminology here. People nowadays mean something else by “Command/Query separation.” But I swear that I first heard the term used (years and years ago) to describe what I consider to be one of the most important principles of method design, and it’s the name I stick with. What I’m talking about is the idea of classifying methods into two broad categories:
- Commands are methods that change the state of the world. To put it another way, they leave visible side effects.
- Queries are functions that figure out a result and give it to you.
To get the full benefit you just need to follow two principles:
- Don’t mix commands and queries. A command method should not return any data. A query function should not have any side effects.
- Use queries to do the heavy lifting.
I find that many C# developers have at least heard of the first of these principles, although it often seems that they don’t appreciate it enough to actually put it into practice (notice that it is yet another consequence of the single responsibility principle). But what I hope to do here is to convince you of the merits of that second principle – putting most of the burden of your system onto queries instead of commands.
The reason for favouring queries should be obvious: they’re so much easier to work with. You ask it a question and it gives you the answer. That’s it. If you accidentally call it twice (while debugging, say), well, you waste some time and resources but otherwise it’s no big deal. And there’s much less concern about complicated interactions between two queries. Worrying about whether it’s safe to call CommandB before CommandA is scary, but what about calling QueryB before QueryA? Sure, why not?! They’re just queries.
And this is what makes the second principle described above so awesome. If most of the burden of your system is placed on queries then that means that your heavy lifting is being done by things that are easy to work with and easy to reason about. What do I mean by ‘burden’? I mean that all of the following logic should be in queries:
- Data retrieval
- Data transformations (e.g. mapping a collection of X’s to create a collection of Y’s).
- Creation of new entities (as in-memory objects)
- Knowledge of the rules of the domain
Notice that creating a new in-memory object usually counts as a ‘query’ because that’s not really changing the world. The query gives you this new object, but you haven’t persisted it yet (that would require a command) so no other part of the system should be affected by its existence (or absence, if you decide to discard it).
Think of it this way: writing queries is the fun part of coding and it’s what you spend most of your time doing. And the whole time you’re doing it you have this peaceful easy feeling because, hey, they’re just queries. Then at the end, you (somewhat reluctantly) write a few commands that do the dicey stuff like updating the database and writing to a log file and sending emails. But those commands are all about orchestrating; anything remotely complicated, anything from the list above – the commands will delegate to queries.
I wonder if anyone has ever figured out a suitable metric for a healthy ‘Query/Command Ratio’. I wouldn’t be surprised if it’s ten-to-one or more.