4 ms·
We use the concepts of commands and queries, where commands can't return anything and queries cannot mutate state. No separate stores for each, though. I thin
by kierenj 7y ago
We use the concepts of commands and queries, where commands can't return anything and queries cannot mutate state. No separate stores for each, though. I think that's either more correctly called CQS, though I remember finding sources that it's just as valid an implementation of CQRS too.
Some advantages:
- Command and query handlers being individual (testable) classes is great for general organisation and neatness
- Beats 'Transaction Script' as a pattern any day
- Can wrap command/query execution with various value-add pipelines: logging, timing, caching (queries)
- Can direct queries to use read replicas
Some dirty tricks:
- Service layer (API endpoint controllers) does pre-validation, declaratively where possible, to enable OpenAPI/Swagger documentation of failure modes
- We do really care about whether commands finish or not - so they do run synchronously in 99.9% of cases. They can be put to a queue, but usually the caller wants to know it finished
- Also, they can throw exceptions with error results.. it seemed a trade-off that's worked well enough
Recently had an idea to steal some concepts from serverless leveraging this: could measure command/query performance, resource use (CPU/RAM) by, based on some heuristic, farming out execution of one or the other to a separate process. Commands, queries and query results all being serialisable.
Event Sourcing and separate stores seemed a bridge too far. It definitely wants loads of expertise/experience and careful design, whereas the above is easy as pie to get going with.
Anyways. It's proved for some enjoyable enough development.
- jddj 7y agoAnother advantage: - Compared with a repository pattern or typical fat-fingered ORM, separating command and query models in code can make it easier to let the data store / search engine do the things it has been optimised to do well on the query end (joins, views, etc), rather than over-fetching data and doing too much of the translation in code.