Skip to content

Command Query Responsibility Segregation (CQRS)

Dan Ludwig edited this page Jan 5, 2015 · 5 revisions

I would be fronting if I claimed to have invented everything in Tripod. In reality, it's just a couple of small original ideas sprinkled over a rehash of things I've learned from others. Two articles in particular have changed the way I think about project architecture ever since reading them (just as the articles claimed they would). They were written by the top geek Steven Van Deursen, the guru behind SimpleInjector. You may need to read them a couple of times, but they present rather brilliant ideas. When I first applied these ideas, it was like swallowing the red pill.

Meanwhile... on the command side of my architecture
Meanwhile... on the query side of my architecture

Now I am by no means an expert on command query segregation. Really, all I know is what I use in Tripod. There are likely other more elaborate code expressions of CQRS that would take issue with Tripod claiming it has anything to do with the term. The CQRS pattern complements another pattern called Event Sourcing, which Tripod does not implement. Digressions aside, the way Tripod uses CQRS is quite simple and extremely powerful. I think it even has a primal quality to it because, when you boil it down, its just a different way to write an encapsulated method.

Have you ever thought about what the difference is between a void method and a method that returns a value? When a method is void, it should have some kind of side-effect. It should change something in the overall business-related state of the application. After all, if it doesn't return a value, what is its purpose? In Tripod's CQRS system, any business code that performs state changes or other side-effect operations (like writing to a database, or sending an email) should be implemented as a Command.

Alternatively, you have the inverse: methods that return values, and make no state changes / perform no side-effects. Examples of this are methods that do math, generate data, retrieve data from an external location, transform data from one conceptual model into another. Invoking them does not change the business state of the system, but it is necessary to have methods for these types of functional operations purely for reasons of encapsulation. In Tripod's CQRS system, any business code artifact whose primary job is to return data should be implemented as a Query.

There is also a third type of method, one that both performs a side-effect and returns a value. Classic examples of these the static TryParse methods (int.TryParse, Guid.TryParse, bool.TryParse, etc.) Another example you may encounter often is when you need to get the automatically-generated ID value back from a database after an INSERT (side-effect) operation. Though you should try a little to avoid methods that both have side-effects and return values, don't try too hard. Sometimes it's the best way. However when you do need them, you should implement them as Commands, not Queries. (Note that trace logging is not considered a business-related side-effect, so feel free to log in Queries.)

##How this will solve all of your project layering problems

It's in those two "Meanwhile..." articles I put near the beginning of this page. I didn't get it the first time I read it, or the second time. But then, as I started to get it, I began to remember the sentence "...everything in the system is either a query or a command and if we want, we can model every single operation in this way." Why is this true? Because the alternative way to do it, without CQRS, is to just write methods. In reality, commands and queries really are methods, just a little more structured. The biggest thing they bring to the table is that they can take dependencies on interfaces which the IoC container can deliver at runtime.

In actuality, each command and each query has 2 parts: the data class and the handler class. You can think of the data class as an encapsulation of method arguments. So if you were going to write a method with 3 arguments, you would instead write a command or query data class with 3 properties. The handler class will accept an instance of the data class as its single argument and provides the body of code that will use the argument data to deliver business value. Although object-oriented languages give us the ability to combine state and behavior, we can gain certain advantages by separating data from behavior.

Let's look at a rather offensive example of how a pimp might use Tripod to write an MVC controller:

public class ThisHustlerController : Controller
{
    private readonly IProcessQueries _queries;
    private readonly IProcessCommands _commands;

    public ThisHustlerController(IProcessQueries, queries,
        IProcessCommands commands)
    {
        _queries = queries;
        _commands = commands;
    }

    [HttpPost]
    public async Task<ActionResult> GiveMeMyMoney(PayMe command)
    {
        if (command == null) return View("SlapHard");
        await _commands.Process(command);
        return View("SlapMedium");
    }

    [HttpGet, Authorize(Roles = "Not the police")]
    public async Task<ActionResult> GetHo(TrickRequest query)
    {
        if (query == null) return View("Hustle");
        var trick = await _queries.Execute(query);
        return View(trick);
    }
}

Notice how it is clear exactly where to draw the line between the MVC controller code and the business code. There is no fancy IPayPimpService or IHoTeamRepository, or any special interface for this controller. Your GET requests will process some kind of query, and your POST / PUT / DELETE requests will process some kind of command. The MVC controller actions are thin, and only deal with passing messages to the domain in the context of HTTP. By doing this we make MVC controller more boring and easier to unit test, both of which are good things.

One final note about this: You may or may not have noticed that I am using business command and query data objects as MVC Models. This is an idea that I got from a developer I talked to one time. You don't have to do it this way: You can have your InputModel and ViewModel classes be specific to the MVC layer, and convert them to commands and queries before passing to the processing methods. You would just need some extra code to pass the MVC model data into a new command or query data object. I like doing it this way because its simpler, and so far, I haven't seen very many good arguments against it.