What is CQRS?

4 min read

Why is CQRS Needed?

Let's assume the following situation:

  • You are building a developer portfolio site called devfolio.
  • In devfolio, developers can connect their GitHub and LinkedIn accounts and retrieve information from those accounts.
  • Both sites have information such as account name, profile picture, bio, registered websites, etc.

As a web developer, you would create a conceptual data model called social_profile_info and build APIs to CRUD it.

CRUD Example

The variables from Github's API and Linkedin's API may differ. (This is entirely different from the actual APIs.) When the product was launched, responses came as shown above, and after receiving them, the server transformed the variable names and stored the information.

Then one day,

  • The variable names in the API provided by Github changed.

So an error occurred on devfolio's server that uses the API provided by GitHub.

CRUD Error about Github API

You modify the server code and redeploy.
The site gets positive reactions after deployment, and now,

  • You can connect accounts from Discord, Slack, Rocket Punch, etc., in addition to Github and Linkedin.

API modifications become more frequent, and every time there's a change, the feature stops working, and in severe cases, the site goes down. You come up with the following solution:

  • What if we update the account information with the raw JSON response as-is, and then extract only the necessary information when displaying it on the website?

CQRS emerged to separate the responsibilities of database updates and reads like this.

What is CQRS?

CQRS (Command Query Responsibility Segregation) is a pattern that separates Command, which handles CUD (Create, Update, Delete) logic, from Query, which handles Read logic.

In the example above, we can illustrate this by separating updating each account's information in the database as a Command and displaying each account's information in the service as a Query.

In the example, we implemented it by separating the write and read data models within the same database, but you can also completely separate the databases themselves. For example, you could use MySQL for the write-only database and Elasticsearch for the read-only database.

CRUD Error about Github API

In such cases, since the Command and Query databases are different, Event Sourcing is often used to maintain consistency (data synchronization) between them.

Event Sourcing is a method where an Event is triggered whenever a Command comes in, and the Query reads that Event to update the data. Typically, a publish/subscribe pattern is used where these events are stored in a queue and the Query reads them to update the data.

For information on the Pub/Sub pattern, I've covered it in a WebSocket-related article. :)

What are the Pros and Cons of CQRS?

CQRS has the following advantages:

  • By separating Command and Query, changes to Command logic don't affect Query logic.
  • As in the case above, even if various types of writes come in, you don't need to change the Command logic, allowing flexible extension.
  • Since Command and Query logic are separated, it's easier to optimize each independently.

CQRS has the following disadvantages:

  • Since Command and Query logic are separated, when using an ORM optimized for CRUD, it actually increases complexity by adding more code.
  • If Event Sourcing is implemented asynchronously, data updated by Command is not immediately reflected in Query. (It takes some time to be reflected.)

Should You Use CQRS?

Due to these pros and cons, CQRS is not suitable for all services. However, for specific services, applying CQRS can significantly reduce complexity. Here are examples of services where CQRS should be applied:

  • When the number of reads is much higher than writes and you need to optimize read logic, you can separate them.
  • When business rules for writes change frequently, you can use CQRS to reduce complexity.
  • In Microservice Architecture, you can use CQRS to separate data models for each service.

Reference