Understanding CQRS Myths…………………
CQRS (Command Query Responsibility Segregation) is an architectural pattern that separates the operations that read data (queries) from the operations that update data (commands). The idea behind CQRS is to separate the concerns of reading and writing data so that the system can be optimized for each use case. This separation allows for better scalability, as the read side can be optimized for high-performance read operations, and the write side can be optimized for transactional consistency. The pattern is often used in microservices and event-driven architectures where a system needs to handle high traffic, handle high data volume and provide an optimized read and write performance.
There are several common myths about CQRS (Command Query Responsibility Segregation) that are worth mentioning:
- CQRS is only for complex systems: CQRS can be used in a wide range of systems, from simple CRUD-based systems to complex event-driven systems. It can be a useful pattern for any system that needs to separate read and write concerns.
- CQRS is only for event-sourced systems: CQRS and event sourcing are often used together, but they are not the same thing. CQRS is a pattern that separates read and write concerns, while event sourcing is a technique that records the history of events that have occurred.
- CQRS is only for DDD: CQRS is often used in Domain-Driven Design (DDD), but it’s not limited to DDD. CQRS can be used in any architecture that separates read and write concerns.
- CQRS is hard to implement: While CQRS can add complexity to a system, it’s not necessarily difficult to implement. With the right design and tooling, CQRS can be implemented relatively easily.
- CQRS is only for highly available systems: CQRS can be useful for systems that require high availability, but it’s not limited to that. CQRS can be used in any system that needs to separate read and write concerns, regardless of availability requirements.
- CQRS is a replacement of a traditional database: CQRS is a pattern that separates read and write concerns, it doesn’t replace a traditional database. A traditional database can still be used to store data, but the read and write operations are separated.
It’s important to note that CQRS is not a silver bullet, and it’s not the right solution for every use case. It’s essential to evaluate the pros and cons of CQRS for a specific system and use case, and decide whether it’s the right fit.
The purpose of CQRS is to enable the representation of the same data using multiple models. Not scalability, not availability, not security, not performance. Duplicate data in multiple models.
This is the CQRS pattern the way I both see and implement it. Commands have responses. The projection mechanism defined is abstract without any implementation details. Inside it may be based on events, on state, or even a database view. And finally, there is no glimpse of Event Sourcing. Model the system’s business logic as required by the business domain: Active Record, Domain Model, or Event Sourced Domain Model.
As with every correctly applied tool, CQRS should reduce complexity, not induce it. If your architecture’s complexity grows, you’re doing something wrong.
Separated Databases
When working with CQRS, it’s also possible — but it’s not mandatory — to have separate databases:
- a “read database” only for reading the data and creating materialized views
- and a “write database” only for making changes.
When we deal with more complex applications like microservices or any application that has a high demand for data consumption, the standard approach can become unstable because having much writing and reading in the same database can affect the performance of the application (read and write workloads have very different performance and scale requirements).
Data synchronization delay
The need to coordinate all the separate components listed above — especially in a distributed architecture that values decoupling — creates the first big risk with CQRS: a loss of data synchronization. Patterns like CQRS that often rely on publish/subscribe models are subject to delays in updates and race conditions because the client must wait for updated event data.
To imagine this from a user perspective, consider a web-based retail application that provides customers a viewable list of their unique order history. After placing an order, it may take anywhere from several seconds to a few minutes for that transaction to show up in a customer’s order history screen, meanwhile requiring the customer to refresh the page until the new order appears. Eventually, the event will process, and the customer can refresh the order history page to see the updated information on their screen — but not without the risk that customers get frustrated or confused over the delay.
Developers have tried to mitigate the inherent data synchronization delay in CQRS, such as reworking the read/write process or updating the data models directly. A common response to this is to use a write through cache — typically a NoSQL model — to read data. However, doing that mixes the commands and the reads, which is the exact scenario that CQRS was designed to eliminate.
Before starting development in the CQRS pattern into your system, make sure to do a POC and another testing. creating a proof of concept to test your solution will ensure you arrive at the best version and will save you time and money. Don’t be afraid to get your hands dirty.