Command Query
Responsibility Segregation
(CQRS)
Derek Comartin
@derek_comartin
CodeOpinion.com
Agenda
•
•
•
•
•
•
•

Why?
Typical Architecture
What is CQRS
How to apply CQRS
Other benefits
Why Not?
Takeaways
Why?
•
•
•
•
•
•

Complex Domain
Read & Write Boundaries
Divergent Change
Scalability
Skill Set Segregation
Architecture Choices
Typical Architecture

Data Storage

Domain
Object

Domain
Object

Application Service

Facade

DTO

DTO

Client
Typical Architecture - Client Side

6
Ack/Nak Response

1
5

Request DTO

2

Send DTO to
Server

Display DTO in
View

3

4
Modify/Rebuild
DTO
XML of DTO
<BankAccount>
<Id>123</Id>
<CustomerId>456</CustomerId>
<Type>Savings</Type>
<Overdraft>200.00</Overdraft>

<InterestRate>0.0035</InterestRate>
<Active>True</Active>
</BankAccount>
Typical Architecture - Analysis

•
•
•
•

•

Simple & Common
Tooling: ActiveRecord, ORM, AutoMapper.
Data Driven
Potentially Anemic Domain Model
Hard to scale data storage
Command Query Separation
Every method should either be a command
that performs an action, or a query that
returns data to the caller, but not both.
Command Query Responsibility Segregation

”CQRS is simply the creation of two objects
where there was previously only one.”
-Greg Young
Typical Service
BankAccountService
{
BankAccount CreateBankAccount(BankAccount);
BankAccount GetBankAccount(AccountId);
decimal UpdateBalance(AccountId, Balance);
void UpdateBankAccount(BankAccount);
decimal GetBankAccountBalance(AccountId);
}
CQRS Services
BankAccountReadService
{
BankAccount GetBankAccount(AccountId);
decimal GetBankAccountBalance(AccountId);
}
BankAccountWriteService
{
BankAccount CreateBankAccount(BankAccount);
decimal UpdateBalance(AccountId, Balance);
void UpdateBankAccount(BankAccount);
}
"Defining the CQRS pattern is easy. Realizing the
benefits that implementing the CQRS pattern can
offer is not always so straightforward."
– Microsoft Patterns & Practices
"This simple notion leads to some profound
consequences for the design of information
systems."
–Martin Fowler
Complex Domain
•
•
•

(Distributed) Domain Driven Design
Behavior
Intent
Typical Architecture

Data Storage

Domain
Object

Domain
Object

Application Service

Facade

DTO

DTO

Client
Simple CQRS
Data Storage

Domain
Object

Domain
Object

Application Service

Read Layer

Facade

Facade

Query
DTO

Command
DTO

Client
CQRS - Client Side

6
Ack/Nak Response
(optional)

1
5

Request DTO

2

Send Command
Object to Server

Display DTO in
View

3

4
Build Command
Object
Command = Intent
DepositCommand
{
Guid AccountId;
decimal DepositAmount;
}
CQRS Services
BankAccountReadService
{
BankAccountViewModel GetBankAccount(AccountId);
decimal GetBankAccountBalance(AccountId);
}
BankAccountWriteService
{
void Send(OpenBankAccountCommand);
void Send(DepositCommand);
void Send(WithdrawlCommand);
void Send(DeactivateCommand);
}
More Options
•
•
•

Multiple Models
Domain Model = 3rd Normal Form
Read Model = 1st Normal Form
Read & Write Boundaries
Divergent Change

Data Storage

Domain
Object

Domain
Object

Application Service

Read Layer

Facade

Facade

Query
DTO

Command
DTO

Client
Skill Set Segregation

Data Storage

Domain
Object

Domain
Object

Application Service

Read Layer

Facade

Facade

Query
DTO

Command
DTO

Client
Scalability
Event Storage

Message Queue

Event Handlers

Events
Data Storage
Domain
Object

Data Storage

Domain
Object

Command Handlers
Read Layer

Facade
Message Queue

Command
DTO

Query
DTO
Client
Notes
•
•
•

CRUD (not with DDD)
Not top level architecture
Determine per bounded context
Takeaways
•

•
•

Separate reads and writes between two
objects.
That’s it.
Everything else (DDD, Event Sourcing,
Messaging…) is not CQRS. They just fit
extremely well.
Resources
Greg Young
@gregyoung
goodenoughsoftware.net
Udi Dahan
@udidahan
udidahan.com
Microsoft Patterns & Practices
CQRS Journey

Command Query Responsibility Segregation (CQRS)