disclaimer: if you’ve ever read a ‘for dummies’ book, you know that they are designed to give a pretty decent overview of a topic from experts. Given that, this series is probably mis-named. It should be something more like “cqrs from an idiot” or something, but that’s bad marketing. Anyway, I’ll be pointing out the people who really know their stuff, with links and whatnot, but I hope to be able to give an explanation of CQRS at a high level that will be of use.
update: adding missing overview paragraph at the end, and uploaded larger pictures.
Goals for the series
Anyone who has looked at my DDD-Lite series might wonder about the relationship between CQRS and DDD. Glad you wondered. Put crudely, DDD fits inside of CQRS. That is, the latter is an architectural style that uses a Domain Model, but goes beyond it. You can do DDD without doing CQRS. It is technically possible to do CQRS without DDD, but they fit together well.
What I want to try to do is to layout what I take to be the basic tenets of CQRS in a way that might be easier to understand in some circumstances. A full-blown implementation of CQRS involves a lot of concepts that have a lot of implications, some of which, in my opinion, are not logically required. The concepts that I want to focus on are ones that I think that any experienced developer/architect should be able to understand, and which can provide a very robust and maintainable way of developing software.
“Okay, last week it was DDD, now it is CQRS, what’s next, XYZ?” Possibly, yes. I think that CQRS is proven by the main practioners who have used it in high-demand, highly scalable environments (think real-time stock trading), and as such, is usable in many different situations. Are you going to want to implement it for every possible software application? No, of course not. But, if you have an application that is similar to, say, your everyday eCommerce application in terms of complexity, I think it is something to look at. It preaches techniques and practices that are pretty widely applicable.
And, as for whether there will be some XYZ that further expands on CQRS….sure, it’s possible. It might even be desirable. When done right, real world experience leads to refinements of accepted practices. It’s called learning.
What is CQS?
CQS is the acronym for “Command Query Separation” and was presented by Bertrand Meyer (via Wikipedia) as follows:
“every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.”
In my own words, a query should ask a system about its state without affecting it, whereas a command affects the state of a system. Moreover, these things should be separate in software. That is, a query should return something (more on what this something is in a bit) that details the state of the system you care about, while a command should be a void method call (or maybe returns an int or bool to indicate the result of issuing the command) that changes the state of the system.
Trivial examples run the risk of being, well, trivial, but think of a basic eCommerce system. If I want to display a list of pending orders, I want to issue a query that gives me the list of pending orders, without changing the state of any of them. If I want to change the state of an order from ‘Pending’ to ‘Fulfilled’, I want to issue a command that does just that.
If you’ve ever worked with a system that mixes queries and commands, you know how difficult that system is to work with. Does this method call change things or not? How do I know? Is there some global variable that I need to track?
What is CQRS?
CQRS is the acronym for “Command Query Responsibility Segregation”, which I believe was coined by Greg Young, in this post. In any event, the important point is this:
Separate command methods that change state from query methods that read state.
Separate command messages that change state from query messages that read state.”
On the face of it, it doesn’t seem like that big of a deal, but the architectural implications are pretty important. This will become clearer shortly.
The people who I’ve learned about CQRS from are among the following:
Greg Young: you can learn a lot by reading his posts here. He doesn’t post much these days, but he did coin the acronym.
Udi Dahan: in particular, he talks about his current thinking about CQRS here.
Mark Nijhof: he has a reference implementation available here and gives a good overview here. As you will see, I’m using a couple of his images, right about…….now.
Picture One from Mark
With permission, here’s an image of a potential CQRS implementation:
With permission, here’s the same image split into sections:
The four sections that Mark separates are these:
- Internal Events
- External Events
I will comment on all four sections, but just to highlight section #1, think of the following:
Suppose you need to display to a user the order information that is tied to a particular customer, a typical requirement for some screen (windows or web).
If you are using a Domain Model, you might have a Customer object. Tied to that Customer object is the list of the orders associated with it. A typical way of handling this in software is to load the Customer object from a database, and then load the associated orders. Then, you translate that Customer object to a DTO that contains all of the relevant data that is needed in the order information screen, and that DTO is passed to your UI.
This is pretty typical. If you code the way I do, you have some sort of mapper class that maps the domain object to the DTO. And this does work.
But….why create the domain object and then map it to a DTO? Why not just create the DTO directly? The DTO won’t need all of the possible data that the domain object contains, so that is wasted communication with your data source. Why spend time mapping at all?
Overview of the 4 sections
- Queries: as noted above, queries produce DTOs that come directly from a facade layer that doesn’t interact with the Domain Model at all. The thin data layer noted in the picture could very well be SQL views that directly map to your ViewModel. These then can easily bind to your UI. So, imagine that when a screen is loaded, it sends a GetCustomerDetailQuery object with the ID of the customer to the data store, and a simple DTO is returned.
- Commands: these are produced by interacting with the UI, perhaps editing the customer information on a screen and pressing the update button. This will produce something like a ChangeCustomerAddressCommand object which is then sent into the system to be handled (validated and then sent into the Domain, or rejected, or, etc. etc. etc.). Mark’s pictures denote that a bus is specifically used, but it doesn’t have to be done this way (though you probably should).
- Internal Events: here is where the commands interact with the Domain Model, and where the concepts of a repository and an Event Store come into play. In my mind, understanding the Event Store and how it works is the most complicated part of CQRS. A couple of things to note: the Event Store is write-only and it doesn’t have to be a database (in fact, if I understand it correctly, it usually isn’t). It could be a database though, but we’ll cover this in detail later. The notion of a Compensating Action will also come into play.
- External Events: once the Domain has been updated by the internal events, these events are published so that any subscriber can be made aware of them. These could be external vendors, but in the diagram, you see that the read/write database that is the source for the Query objects is also a subscriber. This can be confusing to understand properly. Doesn’t this mean that your database can be out of sync with what is happening in your Domain? Yes, it can, but as you will see, this isn’t really a problem, because it already happens in your systems today. As importantly, you will find that architecting a system this way greatly enhances scalability, and the notion of Eventual Consistency will come into play.
What’s to come
What I want to do next is to discuss the four sections in more detail, and how it might affect the architecture of a typical software application.