CQRS Design Pattern — 5 Things You Should Know
What Is CQRS Design Pattern?
CQRS (Command Query Responsibility Segregation) is an architectural pattern that separates write(create/update/delete) data stores from query data stores.
Command or write actions, as well as complicated query activities, are traditionally executed against the same backend storage. However, there are a lot of scaling problems associated with this. Both write and query patterns must be supported by the table schema. Also, query patterns vary widely, and adding new queries necessitates the creation of indexes or the execution of a join against a separate table, both of which have an influence on performance and availability at scale.
CQRS employs two data models: one for reading input and the other for mutating state. CQRS encourages the asynchronous generation of materialized views that are specially designed and optimized to handle any complex queries.
Why Use CQRS Design Pattern?
In the past, a single object model or domain model was created that had to process changes and at the same time provide all answers to queries. Over the years, it was learned that a single model or a single view is not capable to satisfy all use cases optimally. With CQRS:
- You do not have to conflate your write schema with your query schema.
- You no longer need to lock table/record for updates which can impact performance.
- You no longer need to perform table joins because you can denormalize and customize your data specifically for your required query.
- You can add support for new queries by creating a new materialized view without impacting performance and availability of your write store or other query stores.
- You can take customization a step further and use different storage technologies depending on the requirements of a query. For example, certain queries might be better served by a graph database.
- You can scale and optimize command and query parts separately.
Known Problems Of CQRS
All of above benefits allow services to scale much higher than a traditional RDBMS based solution. However, there are tradeoffs to using this technique:
- Since the query storage is populated asynchronously, data becomes eventually consistent.
- System may lose ACID transaction properties across entity boundaries. However, various helpful techniques have been developed for handling transactional requirements without ACID.
- The storage costs increases as multiple copies of data is maintained(n tables for queries in addition to authoritative table for writes).
- Troubleshooting is difficult due to additional code paths/point of failures.
- Additional infrastructure and data access layer code is required to maintain materialize views.
Implementation Details
CQRS systems can be implemented in functional or object-oriented way. All changes are made by interpreting incoming commands and applying them to the domain model. All queries are completed by using one or multiple read models to process incoming query requests. Read models are often isolated microservices that do not disrupt the processing of changes (commands).
System should also be comfortable with the concept of eventual consistency. This simply means that data will eventually be persisted and it may happen at different times. So, being aware of eventual consistency means that you embrace the network between the components in your solution and that time can be a critical factor when information is needed. As long as you are aware of this, you can design your architecture in such a way that eventual consistency is not a problem but something that you can take advantage of.
Practical Examples Of CQRS Design Pattern
The following sample of mature industries are great use cases of CQRS:
- Finance — To achieve compliance, all financial businesses require robust data storage and auditing solutions that provide immutable audit logs and a single source of truth.
- Retail — Large retailers and e-commerce providers must deal with various systems and data sources, and they must progressively analyze data in near real-time to create tailored shopping experiences and optimize purchase and operational decisions for customers.
- Technology — Tech companies that provide services such as SaaS solutions or trading applications need high-performance data model that scales and an improved capability to spin up new microservices connected to their central data model to adapt and change in order to compete.
- Transport — Companies that engage in operations such as shipping, freight, and logistics have requirements to track shipments accurately and in near real-time in order to give a smooth experience to their consumers.
CQRS approach becomes especially important in case of Domain Driven Designs as each component may require a different representation of domain.
Thank you for reading! If you found this helpful, here are some next steps you can take:
- This blog is part of my System Design Series. Check out the other blogs of the series!
- Send some claps my way! 👏
- Follow me on Medium & subscribe below to get a notification whenever I publish! 📨