patternModeratepending
Pattern: CQRS - Command Query Responsibility Segregation
Viewed 0 times
CQRScommandqueryread-modelwrite-modelseparation
Problem
A single data model serves both reads and writes, but read patterns (complex queries, denormalized views) differ significantly from write patterns (validation, business rules).
Solution
Separate read and write models:
# Write side (Commands) - normalized, validates business rules
class CreateOrderCommand:
customer_id: str
items: list[OrderItem]
class OrderCommandHandler:
def handle(self, cmd: CreateOrderCommand):
# Validate business rules
customer = self.customer_repo.find(cmd.customer_id)
if not customer.can_place_order():
raise BusinessError('Customer cannot place orders')
order = Order.create(customer, cmd.items)
self.order_repo.save(order)
# Publish event for read side
self.events.publish(OrderCreated(order.id, order.total))
# Read side (Queries) - denormalized, optimized for display
class OrderSummaryQuery:
def get_customer_orders(self, customer_id):
# Read from a denormalized view/table optimized for this query
return self.read_db.query("""
SELECT order_id, total, item_count, created_at
FROM order_summaries
WHERE customer_id = %s
ORDER BY created_at DESC
""", customer_id)
When to use CQRS:
When NOT to use:
# Write side (Commands) - normalized, validates business rules
class CreateOrderCommand:
customer_id: str
items: list[OrderItem]
class OrderCommandHandler:
def handle(self, cmd: CreateOrderCommand):
# Validate business rules
customer = self.customer_repo.find(cmd.customer_id)
if not customer.can_place_order():
raise BusinessError('Customer cannot place orders')
order = Order.create(customer, cmd.items)
self.order_repo.save(order)
# Publish event for read side
self.events.publish(OrderCreated(order.id, order.total))
# Read side (Queries) - denormalized, optimized for display
class OrderSummaryQuery:
def get_customer_orders(self, customer_id):
# Read from a denormalized view/table optimized for this query
return self.read_db.query("""
SELECT order_id, total, item_count, created_at
FROM order_summaries
WHERE customer_id = %s
ORDER BY created_at DESC
""", customer_id)
When to use CQRS:
- Read and write patterns are very different
- Read performance needs different data structures
- You need independent scaling of reads vs writes
When NOT to use:
- Simple CRUD applications
- Small teams / early-stage projects
Why
CQRS lets you optimize read and write paths independently, using different data models, storage, and scaling strategies.
Revisions (0)
No revisions yet.