Why And How To Use CQRS Architectural Pattern

CQRS stands for Command Query Responsibility Segregation. CQRS is an architectural pattern. It says that the data read operation and data write operation should be separated.

Example of bad design without CQRS

  1. public interface IStudentRepository  
  2. {  
  3.     Customer GetById(int studentId);  
  4.     Customer GetByEmail(string email);  
  5.     int Save(Student student);  
  6.     void Delete(Student student);  
  7. }  
The example given above contains four methods, where two are related to read and two are related to write. As per the architectural pattern, first two reading operations should be in one interface and other writing operation should be in a different interface.

With CQRS
  1. public interface IStudentRepositoryRead  
  2. {  
  3.     Customer GetById(int studentId);  
  4.     Customer GetByEmail(string email);  
  5. }  
  6. public interface IStudentRepositoryWrite  
  7. {  
  8.     int Save(Student student);  
  9.     void Delete(Student student);  
  10. }  
Reason and Benefit to of CQRS 
  1. Reading the data is more frequent than writing. Generally, it is in ratio of 10:1 or sometimes 100:1.
  2. Reading operation should be fast. A user feels frustrated, if a query takes more than half second.
  3. The user can tolerate the write operation slowness, as they know that some important action happens in the system.
  4. Write operation changes the state of system. World looks different before and after the write.
  5. Read operation wants to retrieve quite a bit of data while writing effects only one or two rows at a time.
  6. Write operation changes the state. Thus, they have the side effects.

Reading data

Since reading the data should be fast enough,  we should make sure of the following.

  1. The data should be accessed in a manner, which needs least amount of DB queries possible for necessary context only.
  2. Aggregated data should not be calculated on the fly. Rather it should pre-calculated.
  3. No business logic should be executing while reading the data. It should execute while writing.
  4. Read operation should not have any side effect because they do not make any change.

Writing data

  1. Writing operation should not return any result except the status message (success or failure).
  2. Write should send the limited set of the data, which is mostly one row at a time to write or update.

Like

  1. public class AddProductToShoppingCart  
  2. {  
  3.     public int ShoppingCartId {  
  4.         get;  
  5.         set;  
  6.     }  
  7.     public int ProductId {  
  8.         get;  
  9.         set;  
  10.     }  
  11.     public int Quantity {  
  12.         get;  
  13.         set;  
  14.     }  
  15. }  
The code given above will send only one item to be added in the cart.