CQRS Pattern and Event Sourcing Explained

Chaitanya (Chey) Penmetsa
CodeNx
Published in
5 min readFeb 7, 2024

CQRS, which stands for Command and Query Responsibility Segregation, is a pattern designed to partition read and update operations for a data store. By incorporating CQRS into your application, you can enhance its performance, scalability, and security. The adoption of CQRS introduces flexibility, enabling a system to evolve more effectively over time while mitigating potential merge conflicts caused by update commands at the domain level.

Context and Problem

In conventional architectures, a unified data model is employed for both querying and updating a database, which is suitable for basic CRUD operations. However, in more intricate applications, this approach can become cumbersome. For instance, on the read side, the application may execute various queries, generating data transfer objects (DTOs) of varying structures, leading to intricate object mapping. On the write side, the model might encompass intricate validation and business logic, resulting in a model that is excessively complex and multitasking. Furthermore, read and write workloads frequently exhibit asymmetry, featuring distinct performance and scalability demands.

  • A misalignment frequently arises between the read and write representations of data, introducing additional columns or properties that must be accurately updated despite not being essential for an operation.
  • Data contention may arise when operations are executed concurrently on the same dataset.
  • The conventional approach can adversely impact performance, attributable to the burden on the data store and data access layer, along with the intricacy of queries needed to fetch information.
  • Handling security and permissions can become intricate, as each entity is susceptible to both read and write operations, potentially exposing data in an inappropriate context.

Solution for above problem

CQRS (Command Query Responsibility Segregation) is an architectural pattern that advocates for separating the concerns of reading and writing data into distinct models within an application.

Commands, which are used for updating data, should focus on tasks rather than specific data changes. For instance, instead of “set ReservationStatus to Reserved,” a command might be “Book hotel room.” This shift in perspective often requires adjustments to user interaction patterns. Additionally, enhancing the business logic handling these commands can increase their success rate. Validating user inputs on the client side before sending commands can prevent unnecessary server-side failures. For example, disabling booking buttons and providing explanations on the user interface (UI) for unavailability of rooms can preemptively address potential issues. By minimizing server-side command failures to race conditions, such as multiple users attempting to book the last available room simultaneously, and employing additional data and logic, even these rare occurrences can be mitigated.

Commands can also be queued for asynchronous processing instead of being executed synchronously, improving system responsiveness and scalability. In contrast, queries, which are exclusively used for reading data, do not modify the database. They return Data Transfer Objects (DTOs) devoid of any domain-specific knowledge, ensuring separation of concerns and simplifying data retrieval processes.

Event Sourcing

The CQRS (Command Query Responsibility Segregation) pattern is frequently employed in conjunction with the Event Sourcing pattern. In systems based on CQRS, data operations are split into distinct read and write models, each customized for specific tasks and often residing in separate storage locations. When paired with Event Sourcing, the collection of events serves as the write model, acting as the authoritative source of information.

Utilizing the stream of events as the write storage mechanism, instead of the current data snapshot, helps prevent conflicts when updating a single aggregate and enhances both performance and scalability. These events can then be employed to asynchronously generate materialized views of the data, which are subsequently utilized to populate the read storage. Since the event store serves as the authoritative source of information, it becomes feasible to delete existing materialized views and replay all historical events to construct a new depiction of the current state as the system evolves or when alterations are made to the read model. Essentially, the materialized views function as persistent read-only caches of the data, providing efficient access to frequently accessed information while preserving data integrity and consistency.

Benefits

  • Scalability: CQRS enables independent scaling of read and write operations, potentially reducing contention for locks.
  • Efficient Data Structures: The read side can use a schema optimized for queries, while the write side can focus on schemas optimized for updates.
  • Enhanced Security: It’s easier to control which domain entities have write access to the data.
  • Clear Separation of Concerns: Splitting read and write responsibilities can lead to more manageable and adaptable models. The write model typically handles complex business logic, while the read model remains relatively straightforward.
  • Simplified Queries: Storing precomputed views in the read database allows the application to perform queries without complex joins.

Drawbacks

  • Increased Complexity: While the core concept of CQRS is simple, implementing it can lead to a more intricate application design, particularly when combined with the Event Sourcing pattern.
  • Messaging Challenges: Although not mandatory, CQRS often involves messaging for command processing and update event publication, which introduces complexities related to handling message failures and duplicates.
  • Eventual Consistency: Separating read and write databases may result in stale read data. Ensuring the read model reflects changes in the write model can be challenging, especially when detecting requests based on outdated read data.

I trust this blog has effectively highlighted the significance of CQRS and Event Sourcing. In the upcoming blogs, we will delve into practical implementations, covering an end-to-end solution utilizing CQRS, Event Sourcing, and Event Storming. Our focus will be on a real estate company, demonstrating the implementation using .Net, Kafka, MongoDB, and SQL Server.

For end-to-end coding blogs on CQRS and Event Sourcing Please read below blogs.

🙏Thanks for taking the time to read the article. If you found it helpful and would like to show support, please consider:

  1. 👏👏👏👏👏👏Clap for the story and bookmark for future reference
  2. Follow me on Chaitanya (Chey) Penmetsa for more content
  3. Stay connected on LinkedIn.

Wishing you a happy learning journey 📈, and I look forward to sharing new articles with you soon.

--

--

Chaitanya (Chey) Penmetsa
CodeNx
Editor for

👨🏽‍💻Experienced and passionate software enterprise architect helping solve real-life business problems with innovative, futuristic, and economical solutions.