No, I'm not going to talk about CQRS, but the ideas behind both concepts are similar.

The Command-Query Separation principle was first introduced by Bertrand Meyer in his book Object-Oriented Software Construction. Mr Meyer states as follows:

Functions should no produce abstract side effects.

Meyer differentiates two kind of functions when we design a class:

  • Commands: those functions which produce abstract side effects (change the observable state of the object).
  • Queries: those functions that don't produce any side effect and return some value.

And what is an abstract side effect? Meyer define an abstract side effect as follows:

An abstract side effect is a concrete side effect that can change the value of a non-secret query.

Or, in other words, that change the observable state of the object. A concrete side effect is a change in the internal state of your object but then they restore the original state.

A query should be idempotent, that is should return the same results if we execute it once or one hundred times. So, a query should not change the state of the object.

Imagine for example the Console.ReadLine() method of the .Net framework. This is clearly an example of query that changes the state. We cannot call Console.ReadLine() one hundred times and expect the same behavior. According to this principle we should split this call in two calls: Fetch (a command) and GetLastLine (a query).

Let's see another simple example:

public class Account
{
    private double _balance;

    public Account(double initialBalance)
    {
        _balance = initialBalance;
    }

    public void Deposit(double amount)
    {
        _balance += amount;
    }

    public double Withdraw(double amount)
    {
        _balance -= amount;
        return _balance;
    }

    public double GetBalance()
    {
        return _balance;
    }
}

In this class we have two queries (GetBalance and Withdraw) and one command (Deposit). We can identify queries because they have a return value (although commands can return new objects as well ). If we take a look at Withdraw, we can see that it changes the internal value of balance and return it. So, if we execute Withdraw several times, we will have different results, and that's something we don't expect of a query. In that case we should convert this query into a command, converting it to a procedure and removing the return statement.

Adhering to this principle will increase the maintainability and extensibility of our codebase. Your code will be easier to explain and understand, because you won't have to dig into the class looking for side effects.