Hacker News new | ask | show | jobs
by tekmaven 2587 days ago
I've worked on CQRS / ES microservices at scale and have seen how successful they can be at reliability, scalability and performance.

I don't think people are qualified to reject this pattern unless they've spent some serious time working in these ecosystems. It took me a long time with a ton of production experience to evolve my thinking and truly appreciate CQRS/ES.

3 comments

I've worked in mature CQRS/ES services at scale, I've also helped convert other systems both into proper CQRS, and out of proper CQRS.

Like anything else, it's one tool in the tool bag, but like that giant pipe wrench that you're always looking for a reason to use, it's almost always the wrong tool for the situation. CQRS carries horrific complexity and requires commitment to a handful of golden rules or the entire thing comes crashing down.

> I don't think people are qualified to reject this pattern

I don't think most people are qualified to know what the hell this pattern truly is, much less put it into proper operational use. I've seen plenty of people attempt to use CQRS when they should have stuck to a simple CRUD model. At one point I was adjacent to a team that had built 8+ services to handle one or two trivial business processes.

CQRS isn't a fine wine or stinky cheese. If it smells funny for your case, it probably isn't the right choice.

> requires commitment to a handful of golden rules or the entire thing comes crashing down

What are the golden rules?

Two bigs ones for me:

- Don't use the read side from the write side.

- Each aggregate should own its data (or more abstractly, the basics of DDD, bounded contexts[0]).

[0]: https://cqrs.nu/Faq

Every state change needs to be reflected as event. Does your function need to save something to DB? Then your functionality should create event which will perform the DB save.
> CQRS carries horrific complexity and requires commitment to a handful of golden rules or the entire thing comes crashing down.

As with all software architecture, you need to adopt a concept to the problem at hand: following the "rules to the letter" is hardly useful. Most successful CQRS systems are those that do not follow every rule (e.g. let command handlers return response data make for a much more convenient workflow).

In general yes, but if you say, start using your read data on your write side, then you're in for a very bad time. Likewise you are going to have some very serious timing woes if you violate your domains.

It's easy to read this and go "of course" for a small conceptual system, but in practice even really experienced engineers want to break those rules in production systems - and it's a lot easier to break those rules than fix the system to respect them.

In this specific case I'm talking about e.g. returning errors in case command validation failed. Officially it's supposed to be returned asynchronously through events (and then correlate by the command identifier), but it can be much more pragmatic (and reliable even) to just return an error from the command handler in these cases.
Your writes are always going to return a write model, and that won't account for indexing problems when you don't return an error - so your clients may naively equate a non-error response as a success. If you're the one writing the client, maybe that's not a problem. If you have several consumers who don't know the ins and outs of your system, that might be a very serious problem.

This is the problem with CQRS. The answer to so many of these little tweaks depends on a ton of system knowledge and contracts and promises, and it's really really easy to make the wrong choice.

I don't think people are qualified to reject this pattern unless they've spent some serious time working in these ecosystems.

Fine - but it isn't a matter of rejecting or accepting; but rather of understanding. And if someone isn't "qualified" to reject a certain architectural pattern... then they probably won't be very good at implementing it either.

So on balance I'd rather be in an environment where people are allowed to "reject" what they don't fully understand yet -- rather than (pretend to) go along with it (on the basis of some article they vaguely read about it, or "because X said so.")

I think you are right, though doesn’t your conclusion mean that this pattern, and any pattern that isn’t “simple enough”, is automatically disqualified? I do think that any pattern that is more complex than your business case is always the wrong one.
Like every tool in the toolbox it has a range of proper applications, comes with its own complexities and downsides.

Having tried and failed to apply it shouldn't aautomatically generalize the failure to a problem with the tool, but rather to either its inadequacy to the use case, or its improper use (and this is useful learning as well).