Should you use a CQRS framework?
If you’re just getting into the patterns around CQRS, I’d suggest avoiding frameworks. It’s important to remember that CQRS and Event Sourcing are patterns. Like the Gang of Four patterns, they offer a way to communicate architectural decisions.
I sometimes get asked about the learning path for design patterns in general. I believe that it’s important to be able to communicate patterns, but we shouldn’t get down on ourselves if we can’t implement every GoF pattern from memory.
The benefit we get from a “pattern language” is that we can start to tell each other why we found the need to use a certain pattern. You can start to recognize the thought process that other developers used when you’re reading through a solution.
But back to using CQRS frameworks - what about the non-trivial things that we might need to implement?
- Event Sourcing
- Snapshots, caching
- Unit of Work, rollbacks
- Optimistic/Pessimistic locking
- Validations
- Versioning (of events, of domain logic, of projection logic)
- Process Managers, State Machines
- Integrations (Message Queue, API gateway, Notifications, Web Sockets, Polling)
- Event storage, archiving/rollover, backup, indexing, migration
- Projections/denormalisers
- Deduplication, data cleansing
- Event ordering policy
- Error handling, retry, dead-lettering, alert, circuit breaker
- Scaling, load-balancing, redundancy
- Managing read-model schema changes (e.g. new/alter read models, rebuild projection from entire event history while keeping uptime)
- Administrative tools, e.g. Manual way to fix erroneous domain data, fix read models, view/query domain data
- Operation monitoring, e.g. Monitor the flow of events; monitor eventual consistency, detect excessive delays, data inconsistency
- Security: (e.g. user permission, multi-tenancy) more challenging to enforce in applications backed with event-sourced repositories
These are concerns, yes. But will a framework make these concerns more trivial? The tradeoff is, how much accidental complexity are you introducing with a framework that covers all of these scenarios vs. how much help are you getting from the framework?
Rinat Abdullin wrote about this issue in his Lokad.CQRS Retrospective:
The high-level design problem here was in trying to limit an implementation to a few known possible choices. It is the same as telling people: “I don’t know what you are trying to build, but here are tools and materials for that. By the way, be gentle with that sledgehammer, it could break, if twisted clockwise”.
This is a constraining approach which can lead to a lot of technical debt in later stages of the project.
I remember a couple years ago tweeting my excitement about finding this Lokad.CQRS framework in my travels. I was quickly halted by Rinat:
If we break down our list above and look through the things that Lokad.CQRS was trying to solve for us, we can likely solve these problems with the help of libraries rather than frameworks. Rinat, looking back at what he would have done differently, says:
Lokad.CQRS was created with a very short-sighted design approach in mind, a reusable LEGO constructor.
These days I’d try to limit the damage I inflict upon the developers and avoid writing any widely reusable frameworks. They come with too much responsibility.
At most I’d help to setup a design and development process in a single project or a company:
- Align design with tools and solutions that already exist out there.
- Focus on high-level design, testability and integration, while deferring implementation details.
- Provide developers with means to understand how their implementation behaves in production, allow to optimize it and scale.
- Allow developers to switch between different tools and clouds, instead of coupling them to a single cloud provider.
- While working on the design, start by decomposing the solution into separate contexts, identifying the boundaries and capturing them in the code.
Summary
I don’t want to suggest that all the work that has been put into the various CQRS frameworks out there is worthless. They are valuable as reference code for you to read. But when it comes down to your domain and your environment, I suggest not locking yourself into a framework that tells you what complexities you need to be solving for. It’s more beneficial to discover these complexities from the perspective to your own environment.
P.S. Have you bought Event Sourcing and CQRS with .NET Core and SQL Server yet? Launch end is nearing! After Friday, November 24th, all promo codes, including fpc-v2 for $10 off will EXPIRE. Make sure you grab this offer before it’s too late!
Also, just for you here’s a free sample of Chapter 6 - Projection and the Read Model: PDF, MOBI, EPUB
Head on over to buy the book now!