Skip to content

Cqrs


CQRS stands for Command Query Responsibility Segregation - a pattern that separates read and write operations into different models.

Traditional vs CQRS
===================
TRADITIONAL (CRUD):
+----------------------------------+
| Single Model |
| +-------------------------+ |
| | UserService | |
| | - createUser() | |
| | - updateUser() | |
| | - getUser() | |
| | - listUsers() | |
| +-------------------------+ |
| | |
+----------------|-----------------+
v
+---------+
|Database |
+---------+
CQRS:
+-------------------+ +-------------------+
| Command Model | | Query Model |
| | | |
| - createUser() | | - getUser() |
| - updateUser() | | - listUsers() |
| | | - searchUsers() |
+-------------------+ +-------------------+
| |
v v
+-------------------+ +-------------------+
| Write Database | | Read Database |
| (Normalized) | | (Denormalized) |
+-------------------+ +-------------------+

Command (Write)
===============
public class CreateOrderCommand {
private String userId;
private List<OrderItem> items;
private ShippingAddress address;
}
public class CommandHandler {
public void handle(CreateOrderCommand cmd) {
// Validate
// Business logic
// Save to write DB
// Publish event
}
}
Query (Read)
============
public class OrderQuery {
public List<OrderSummary> getRecentOrders(String userId);
public OrderDetails getOrderDetails(String orderId);
public List<OrderSummary> searchOrders(String query);
}

Complete CQRS Flow
==================
+---------+ +----------+ +----------+ +----------+
| Client | --> | Command | --> | Command | --> | Event |
| Request| | Handler | | Processor| | Store |
+---------+ +----------+ +----------+ +----------+
|
+---------+ +----------+ +----------+ +----------+ |
| Client | <-- | Query | <-- | Read | <-- |Projector| |
| Response| | Handler | | Store | | |<-+
+---------+ +----------+ +----------+ +----------+
1. Command arrives -> Validated -> Processed -> Event stored
2. Event published -> Projector updates read store
3. Query reads from optimized read store
Dual Database Approach
=====================
Write Database (OLTP):
+--------------------+
| PostgreSQL |
| - Normalized |
| - ACID |
| - Current state |
+--------------------+
Read Database (OLAP/Denormalized):
+--------------------+ +--------------------+
| MongoDB | | Elasticsearch |
| - User profiles | | - Search |
+--------------------+ +--------------------+
+--------------------+ +--------------------+
| Redis | | ClickHouse |
| - Sessions | | - Analytics |
+--------------------+ +--------------------+

BenefitDescription
Independent ScalingScale reads/writes separately
Optimized Read/WriteEach model optimized for purpose
Different ModelsRead model can be denormalized
PerformanceQueries don’t impact writes
FlexibilityMultiple read views
Complex DomainsClearer commands vs queries

Use CaseHow CQRS Helps
E-commerceMultiple views: order list, details, analytics
Social MediaFeeds, timelines, notifications
ReportingHeavy queries don’t slow writes
Real-timeDifferent views for different clients
MicroservicesEach service can have own models
E-commerce Read Models
======================
Write: Order Created
Read Models:
+--------------------+ +--------------------+
| Customer View | | Admin View |
| - My orders | | - All orders |
| - Order details | | - Analytics |
+--------------------+ +--------------------+
+--------------------+ +--------------------+
| Shipping View | | Financial View |
| - Tracking info | | - Revenue |
| - Delivery status | | - Tax reports |
+--------------------+ +--------------------+

ChallengeDescription
ComplexityTwo models to maintain
ConsistencyEventual consistency between models
Learning CurveTeam must understand pattern
TestingMore components to test
DebuggingHarder to trace issues
Eventual Consistency
===================
Timeline:
Time 0: User creates order
|
v
Time 1: Write DB updated (order created)
|
v
Time 2: Event published to message queue
|
v
Time 3: Projector updates read DB (ms to seconds)
|
v
Time 4: All read models consistent
User Experience:
- Order created immediately (write confirmed)
- May see "processing" briefly in read view
- Usually within milliseconds

Multiple Read Models
====================
One Command -> Multiple Read Models
Command: Create Order
Read Models:
1. Customer Orders List
- Simplified (id, date, total, status)
2. Order Details
- Full order with items
3. Shipping Tracker
- Shipping status, tracking number
4. Analytics
- Aggregated revenue, counts
5. Search Index
- Full text searchable

Synchronous (Simple)
====================
Client -> Handler -> Write DB -> Return
|
v
Read DB (synchronous update)
Pros: Simple, eventual consistency window smaller
Cons: Write latency includes read update
Asynchronous (High Performance)
==============================
Client -> Handler -> Write DB -> Return
|
v
Event Queue
|
v
Projector (async)
|
v
Read DB
Pros: Fast writes, scalable
Cons: Larger consistency window

PracticeDescription
Start simpleDon’t CQRS until needed
Separate modelsCommands and queries clearly
Event sourcingWorks well with CQRS
Multiple viewsOptimize each read use case
Handle lagShow “updating” state if needed
MonitorTrack consistency lag

Key CQRS concepts:

  1. Separate reads/writes - Different models for different purposes
  2. Command = write - Intent and validation
  3. Query = read - Optimized for specific views
  4. Eventual consistency - Read models may briefly lag
  5. Multiple views - Different read models for different needs
  6. Complex - Use when benefits outweigh complexity
  7. Works with event sourcing - Natural fit

Next: Chapter 15: Serverless Architecture