Command-Query Responsibility Segregation (CQRS) Principle
  • is Command-Query Separation on a larger scale
  • originated with Bertrand Meyer’s Command and Query Separation Principle
  • If you have a return value you cannot mutate the state. If you mutate the state your return type must be void

CQRS - Example

class CustomerService {
	void makeCustomerPreferred(String customerId);
	Customer getCustomer(String customerId);
	List<Customer> getCustomersWithName(String name);
	List<Customer> getPreferredCustomers();
	void changeCustomerLocale(String customerId, Locale locale);
	void createCustomer(Customer customer);
	void editCustomerDetails(CustomerDetails customerDetails);
}

Applying CQRS on the CustomerService would result in two services as shown below

class CustomerCommandService {
	void makeCustomerPreferred(String customerId);
	void changeCustomerLocale(String customerId, Locale locale);
	void createCustomer(Customer customer);
	void editCustomerDetails(CustomerDetails customerDetails);
}

class CustomerQueryService {
	Customer getCustomer(String customerId);
	List<Customer> getCustomersWithName(String name);
	List<Customer> getPreferredCustomers();
}

CQRS - Different Needs

This separation enforces the notion that the Command side and the Query side have very different needs. The architectural properties associated with use cases on each side tend to be quite different. Just to name a few:

Consistency

  • Command: It is far easier to process transactions with consistent data than to handle all of the edge cases that eventual consistency can bring into play
  • Query: Most systems can be eventually consistent on the Query side

Data Storage

  • Command: The Command side being a transaction processor in a relational structure would want to store data in a normalized way, probably near 3rd Normal Form (3NF)
  • Query: The Query side would want data in a denormalized way to minimize the number of joins needed to get a given set of data. In a relational structure likely in 1st Normal Form (1NF)

Scalability

  • Command: In most systems, especially web systems, the Command side generally processes a very small number of transactions as a percentage of the whole. Scalability, therefore, is not always important
  • Query: In most systems, especially web systems, the Query side generally processes a very large number of transactions as a percentage of the whole (often times 2 or more orders of magnitude). Scalability is most often needed for the query side

CQRS - Resources