Lesson 13 / 25
Command Query Responsibility Segregation
Explain CQRS and separate write models from read models.
Different models for different jobs
CQRS splits a system into a command side, which validates and applies changes using a model built to enforce business rules, and a query side, which serves reads from models shaped for screens and reports. The idea comes from Bertrand Meyer's command-query separation, applied at the architectural level by Greg Young. Why bother? In many systems reads outnumber writes heavily and need very different shapes: the order-entry rules care about stock and credit limits, while the "My orders" page wants a denormalised list with product names and delivery status. With CQRS each side can be optimised and scaled separately: the write side might use a normalised relational model; the read side might use denormalised tables, a search index or a cache. CQRS does not require event sourcing, multiple databases or a message broker; those are separate choices.
Commands and queries take different paths
Commands go through the write model; queries read from purpose-built read models kept up to date from changes.
Separate command and query handlers
The command handler enforces rules; the query handler simply reads a ready-made view.
# command side: enforce invariants on the aggregate
def handle_place_order(cmd, repo, outbox):
customer = repo.get_customer(cmd.customer_id)
if customer.credit_blocked:
raise Rejected("credit blocked")
order = Order.place(cmd.customer_id, cmd.items) # validates stock rules
repo.save(order)
outbox.add(order.pending_events()) # e.g. OrderPlaced
# query side: no rules, just a fast read of a denormalised view
def get_my_orders(customer_id, read_db):
return read_db.query(
"SELECT order_id, placed_at, item_summary, status, eta "
"FROM customer_orders_view WHERE customer_id = %s "
"ORDER BY placed_at DESC LIMIT 20",
(customer_id,),
)CQRS is per component, not per company
Apply CQRS to the parts of a system with complex rules or very different read and write needs. A simple CRUD admin screen gains nothing from it and becomes harder to maintain.
Quick check: Does CQRS require event sourcing?
- No; CQRS separates read and write models, and event sourcing is an independent choice
- Yes, always
- Only with Kafka
- Only for read models
Answer
No; CQRS separates read and write models, and event sourcing is an independent choice — CQRS and event sourcing combine well but neither requires the other.