What is CQRS? 

CQRS stands for Command and Query Responsibility Segregation (CQRS) pattern.

It separates read and writes/update data models used for querying and updating the data store.

What is general approach we follow objects used in Read Write query?

Generally, most of the people when creating request response object, they use the same object to query and update a database. This is fine for basic CRUD operations but for complex application this may not be best suited approach.

For Example: You have created API for saving or querying Movie object, then your APIs and data models may look like:

For Creating Movie Object:

API Url: /my-app/movie 
Request Type: Post
Request Body: 
{
  id: null
  name: "The Matrix"
  producer: "xyz"
  actors: [ "abc", "def" ... ]
  releaseDate: x/y/z,
}

To retrieve Movie Object:

API Url: /my-app/movie/1234
Request Type: GET
Response Body:
{
  id: 1234
  name: "The Matrix"
  producer: "xyz"
  actors: [ "abc", "def" ... ]
  releaseDate: x/y/z,
  createdOn: p/q/r,
  createdBy: "admin"
}

Why we need CQRS? 

In more complex applications, this approach of using same read/write objects can become unmanageable. For example:

  • For Read Query: application may perform many different queries to return data transfer objects (DTOs) with different shapes.
  • For Write Request: object model may require some data for validation and business logic.
  • Keeping same object model means, keeping additional columns or properties that must be passed correctly even though they aren’t required as part of an operation.
  • Traditional approach sometimes have a negative effect on performance due to load on the data store and data access layer, and the complexity of queries required to retrieve information.
  • Managing security and permissions can become complex, because each entity is subject to both read and write operations, which might expose data in the wrong context.

As a result, you can end up with an overly complex model that does too much.


Solution
CQRS separates reads and writes into different models, using commands. These commands should be task based, rather than data centric. (“Book hotel room”, not “set ReservationStatus to Reserved”).

Apart from separating read and write model, how can we further improve isolation? 

Not necessary, but you can physically separate read data from write data for greater isolation. And read database can use its own data schema that is optimized for queries.

For example, read DB can store a materialized view of the data, in order to avoid complex joins or complex ORM mappings.

It might even use a different type of data store. For example, the write database might be relational, while the read database is a document database.

If separate read and write databases are used, they must be kept in sync. One way to do that is write operation publish an event whenever it updates the database.

Note: If you look at few system designs, for example of AirBnb, you will find that they use 2 databases: 1st a relational database, say MySQL where Hotel information is stored by Hotel Owner and 2nd a database specifically for read operations say Elastic Search DB or Cassandra. Data is transferred from 1st DB (MySQL) to 2nd DB (Elastic Search DB) via some events.

What are the advantages of having separate DB for query?

First note that, this is not required in all cases and for sure every component you add to your design increases the complexity and maintenance cost of design. But if you are creating customer facing app and one of your primary business functionality is to provide search or read operations, you may use separate Read Data Store.

Advantages:

  • Read DB can store a materialized view of the data, in order to avoid complex joins or complex ORM mappings.
  • Having separate Read DB also gives you opportunity to use a Database better suited for read and search operations.
  • You can have separate policy of replication, redundancy of read data store, which can increase query performance, especially in distributed scenarios where read-only replicas are located close to the application instances.
  • Separation of the read and write stores also allows each to be scaled appropriately to match the load.

What is Event Sourcing Pattern? 

First of all, why we are talking about Event Sourcing Patter here is because some implementations of CQRS use the Event Sourcing pattern.

As per Event Sourcing Pattern:

  • Application state is stored as a sequence of events.
  • Each event represents a change to the data item.
  • Whenever user updates the data, the update request is sent in form of event.
  • System, instead of directly updating the data, stores the event first and then may choose to update the latest version of data or may always create latest state by combining all such past events.

Advantage: Current or historic state can also be constructed by replaying the events.

Now when use this pattern in context of CQRS, consider you are sending same event to notify other components — in particular, to notify the read model. The read model uses the events to create a snapshot of the current state, which is more efficient for queries.

Note: Event Sourcing adds complexity to the design.

What are the Benefits of CQRS?

  • Independent scaling If you plan to use different data stores for read and write operations, then you can scale these datastores based on number of read and write requests you will get.
  • Data schemas optimized for read and write operations The read side can use a schema that is optimized for queries, while the write side uses a schema that is optimized for updates.
  • Security It’s easier to ensure that only the right domain entities are performing writes on the data.
  • Separation of concerns Segregating the read and write sides can result in models that are more maintainable and flexible. Most of the complex business logic goes into the write model. The read model can be relatively simple.
  • Simpler queries By storing a materialized view in the read database, the application can avoid complex joins when querying.

What are different implementation issues and considerations you should keep in mind when implementing CQRS?

  • CQRS code can’t automatically be generated from a database schema using scaffolding mechanisms such as O/RM tools.
  • Complexity. The basic idea of CQRS is simple. But it can lead to a more complex application design, especially if they include the Event Sourcing pattern.
  • Messaging. Although CQRS does not require messaging, it’s common to use messaging to process commands and publish update events. In that case, the application must handle message failures or duplicate messages. See the guidance on Priority Queues for dealing with commands having different priorities.
  • Eventual consistency. If you separate the read and write databases, the read data may be stale. The read model store must be updated to reflect changes to the write model store, and it can be difficult to detect when a user has issued a request based on stale read data.

Rakesh Kalra

Hello, I am Rakesh. I have more than 15 years of experience working on IT projects, where I have worked on varied complexity of projects and at different levels of roles. I have tried starting my own startups, 3 of those though none of it were successful but gained so much knowledge about business, customers, and the digital world. I love to travel, spend time with my family, and read self-development books.

%d bloggers like this: