The Command Query Responsibility Segregation (CQRS) pattern
Pattern · Chapter 7
The problem with a single model
Section titled “The problem with a single model”- Traditionally one object model serves both reads and writes, forcing compromises:
- The same entity representation must cover all CRUD operations → bloated classes carrying every property for every scenario.
- Security/authorization is harder because each class is used for both read and write.
- In collaborative domains, parallel operations on the same data risk contention (locking) or update conflicts.
- Read and write workloads have different performance and scalability needs.
The CQRS solution
Section titled “The CQRS solution”- Split into two models:
- Query model → responsible for reads. Query objects only return data and do not alter state.
- Command model → responsible for updates. Command objects alter state and do not return data.
- Principle: asking a question should not change the answer. Mutating state requires a command.
- Reads go through the query model, writes through the command model; a command may read only what it needs to complete.
- Optional next level: separate databases per model, each with a schema optimized for its use. The two stores must then be kept in sync (often via events).
Pairing with event-sourcing
Section titled “Pairing with event-sourcing”- Not required, but CQRS and event-sourcing complement each other.
- Events communicate state changes so the query model stays current as the command model updates.
- The event store (source of truth) lets you replay past events to rebuild the query store’s denormalized data.
Advantages
Section titled “Advantages”- Well suited to complex domains; SoC minimizes and manages complexity → more maintainable, extensible, flexible.
- Teams can split: one on the query model, one on the command model.
- Performance: optimize each schema (query store can be denormalized for fast reads).
- Scalability: scale read and write workloads independently.
- Security: each class is read-only or write-only → easier to enforce and test, less risk of exposing data/operations.
Disadvantages
Section titled “Disadvantages”- Overkill for simple CRUD; adds complexity, especially with event-sourcing. Apply only to the subsystems where it pays off — not necessarily the whole system.
- Separate read/write stores → reads may return stale data.
- With separate databases, the system follows an eventual consistency model (some delay before read store catches up) — contrasted with a strong consistency model where changes are atomic and transactions complete only when all changes succeed (or roll back).
Citations
Section titled “Citations”- Software Architect’s Handbook (Packt, 2018), Ch.7 “The Command Query Responsibility Segregation pattern”, pp. 551-557.