CQRS.
Separate the model that changes state (commands) from the model that reads state (queries), so each side can be modeled, scaled and optimized independently.
##Intent
Use one model to update information and a different model to read it. Commands express intent to change state; queries return data shaped for display. The two no longer have to compromise on a single shared representation.
##Problem
In a traditional design, one model serves both writes and reads. Writes need rich validation and invariants; reads need denormalized, display-ready shapes — often many different ones for different screens and reports.
Forcing both through the same objects and tables leads to awkward compromises: over-fetching, complex ORM mappings, lock contention, and a model that is good at neither job.
##Solution
CQRS splits the system in two. The write side handles commands through handlers that load an aggregate, enforce invariants and persist the change (optionally emitting events). The read side serves queries from one or more read models shaped specifically for the views that consume them.
The two sides can share a database or use separate stores. When they are separate, read models are kept up to date by projecting the write side’s events, accepting eventual consistency in exchange for independent scaling and simpler queries.
##Structure
- Command — a request to change state, named for intent (
PlaceOrder). - Command handler — validates and applies the command to the write model.
- Write model — aggregates that enforce invariants; may emit events.
- Read model / projection — denormalized views built for queries, updated from events.
- Query & query handler — read-only requests served from the read model.
##Applicability
- Use it where reads and writes have very different shapes or loads — many read views, heavy reporting, or a high read-to-write ratio.
- Use it for task-based UIs and collaborative domains, where it pairs naturally with Domain-Driven Design and event sourcing.
- Avoid it for simple CRUD; a single model is simpler and the split adds cost without payoff.
##How to Implement
- Model commands as explicit intentions rather than generic updates.
- Route each command to a handler that loads the relevant aggregate and enforces its invariants.
- Persist the change and, if using events, publish what happened.
- Build read models tailored to your views; if separated, update them by projecting events.
- Serve queries directly from the read models — no domain logic on the read side.
##Pros & Cons
- Read and write sides can be modeled, optimized and scaled independently.
- Each model stays small and focused on one job.
- Fits task-based UIs and composes well with event sourcing and DDD.
- Read models can be tailored per view, eliminating awkward joins.
- More moving parts and more code than a single CRUD model.
- Separate read stores introduce eventual consistency, which the UX must handle.
- Easy to over-engineer; rarely justified for simple domains.
- Operational overhead of projections and message plumbing.