Now that I have completed the long project that has sucked up a huge amount of time (which was necessary because it was important to the client, and because it pays the bills), I have returned much of my attention to one of my own projects, which might hopefully help pay some of the bills down the road and which involves an oddly opinionated version of CQRS.
As it happens, Udi Dahan has written a post entitled “When to avoid CQRS” that suggests I shouldn’t be putting in the effort. Some of the key snippets here:
“It looks like that CQRS has finally “made it” as a full blown “best practice”. Please accept my apologies for my part in the overly-complex software being created because of it.”
“Most people using CQRS (and Event Sourcing too) shouldn’t have done so.”
“Therefore, I’m sorry to say that most sample application you’ll see online that show CQRS are architecturally wrong.”
“So, when should you avoid CQRS? The answer is most of the time.”
Given all of that, it would seem that, for the most part, putting in all this effort has been a mistake.
Rinat Abdullin then posted a response that suggests perhaps things aren’t so grim. Some of the key snippets here:
“In essence, synergies within CQRS work, whenever you need to:
- tackle complexity;
- distribute teams;
- scale out under massive loads.”
“Yet, for some strange reason, the mental model of CQRS provided much friendlier and faster implementation route here.”
So, what should we make of this?
My response is going to be that both Udi and Rinat are correct. To see why seemingly disparate viewpoints could both be correct, you have to consider context.
Isn’t CQRS supposed to be about simplicity?
That’s a bit of an over-statement, but think about what Greg Young has talked about in terms of what I call ‘strict CQRS’. It’s about separating your commands from your queries in your code. That’s it. CQRS doesn’t mean event sourcing, in particular.
Think about the whole concept of a thin view layer as Udi has described. No translating through your domain model, no mapping of Domain objects to DTOs, or any of that stuff, just reading a simple view model (where your queries don’t even have to go through a layer of any kind, just straight from your denormalized data source). That’s it.
A lot of the complexity in CQRS frameworks comes in when you try to implement Event Sourcing and re-creating an AR off of the event store. But what if you take some of the simple principles of CQRS and apply (pun intended) only those, before you embrace full blown Event Sourcing architectural principles?
An EventLog doesn’t have to be gold-plating
“Architectural gold-plating / stealing from the business.
Who put you in a position to decide that development time and resources should be diverted from short-term business-value-adding features to support a non-functional requirement that the business didn’t ask for?
If you sat down with them, explaining the long-term value of having an archive of all actions in the system, and they said OK, build this into the system from the beginning, that would be fine. Most people who ask me about CQRS and/or Event Sourcing skip this step.”
Imagine if you build a system that has some of the architectural principles of CQRS but doesn’t try to implement full-blown Event Sourcing? You can still have your commands being handled (and saved to a command store) and generating events (which are saved to an event store) which are published and subscribed to, and dealt with accordingly, but the state of your domain objects are saved in a traditional, boring database.
The infrastructure for such a system can be pretty simple (more or less). Your event store can still give you a (mostly for) free log that can still give you insights into the history of how your application is used. It doesn’t, obviously, let you replay events to rebuild a system from some particular point in time. You do need to build additional infrastructure for that.
But then is it still CQRS?
Yes and no. You can argue semantics forever, and if you want to do that, you can. But the idea I’m expressing here is that you can gain a lot of benefits from applying some of the basic/strict CQRS principles in a low cost manner.
I don’t know that anyone has ever claimed this, but in my mind, when I think of a domain where full blown CQRS + Event Sourcing makes sense is in a full-blown, real-time trading system. A lot of what I consider to be basic/strict CQRS is probably just coming to terms with understanding basic messaging concepts.
CQRS is a helpful mental model
“Yet, for some strange reason, the mental model of CQRS provided much friendlier and faster implementation route here (despite the fact that there is not a single book published on the subject, yet). Diverse solutions being delivered to production, share similar architecture, development principles, reduced complexity levels and teams. They just work.”
Some of what I’ve taken from in learning what people have been talking about with CQRS is probably really just getting down to brass tacks and learning how to apply SRP.
Every action in my application that changes state is a command, and that command completely consolidates all of the information needed for the state to be changed. It doesn’t include any other information.
Every request in my application for data is a query, and that query completely consolidates all of the information needed to get the data that I need. It doesn’t include any other information.
From just thinking about these two things, I learn quite a lot about what to do with the infrastructure of my application. I don’t need to create a domain object that then gets transformed for every command or query I need to produce. Once I have simple commands and queries, I can do a lot of pretty simple things without having to build a really complicated infrastructure.
In the long project I just completed, I did something like that. I had commands and I had queries. I didn’t have events and I didn’t even implement command handlers, but instead had each ICommand implementation implement an Execute method. One could argue that what I did was simply implement ‘bad’ Transaction Script procedural code, but you know what, I’m fine with that. The system (which was an entirely back-end system with no UI) is now such that, if there is a failure, it occurs within the single Execute method of a single ICommand implementation.
Is this really CQRS? You could very easily argue that, no, it is not. But, I’m fine with that. It used principles and concepts from CQRS that helped make the existing application better, and that met the need that I had with application in question.
Should you avoid CQRS?
It is completely unfair, and, technically speaking, rather inaccurate, but I would recast this question in large part to asking whether you should avoid Event Sourcing. The answer to that is, usually yes. Think of commands (and the events they produce) and queries as messages, and then learn better ways of dealing with messaging.
To take another route, if you do try to go the more ‘advanced’ CQRS framework route, ask yourself a basic question. Suppose you avoided some of the intricate problems you can get when you submit commands that you don’t know for sure will succeed, and so you don’t know for sure how to handle letting the caller (be it a UI element or not) handle when it fails down the road (so to speak). Why not make the whole process be synchronous? A command is created, sent, and handled, and the resulting events from that command are then published. Technically, you don’t know for sure that once an event is published that the subscriber you care about picks it up and processes it. So, as a thought experiment, why not have the calling code that creates and sends the command subscribe to the event publisher that tells you it worked?
If that’s too complicated, as it could be, why not set up your command handler infrastructure to allow you to create command handlers that have a return value? This is something that ‘breaks orthodoxy’ that I’ve had some success with.
It hasn’t been a waste of time
As with everything else in software development, you have to use judgment. I am very ‘unorthodox’ in the sense that I don’t think it is a requirement that you be a software craftsman, or use TDD, or even have unit tests, in order to create successful software.
When it comes to CQRS, though I attempt to understand all of the most sophisticated concepts involved in the most sophisticated expressions of it, I pick and choose the pieces that I think are the easiest and most productive. Part of this is simply understanding my own limitations, where I know I’ll never be the greatest software developer in the world. Part of this is simply understanding the limitations of the applications that I deal with, where I know that e.g. Event Sourcing is something that is genuinely overkill or gold-plating.
I still think that learning CQRS in toto can help you greatly as a developer to find ways to make your applications better.
And I don’t think you need any justification other than that.