The Command and Query Responsibility Segregation invented by Gregory Young in the year 2010 has evolved significantly. It has two objects for the read/write operation. A command is what changes the state of an object but cannot return any information. The query returns the value/information about the state of an object. Divide the query operations and commands into two different layers. Each layer has its own data model while the database is central.
Benefits of CQRS:
- It uses two APIs one for writing data and another for reading
- Optimize the reading and writing processes if performance is critical
- Good for load balancing and scaling applications
- Independent scaling of read and write workloads resulting in lesser disputes
- Reduces stress on the database by enabling easy read/write of cache data from the database
- Quick processing of large amounts of data
- Increase in precise delivery to the actual user who raised a query
- Great for building new products/systems
- Defining business preferences of transactions allows you to describe the needed consistency levels
- Schema optimized for queries is used to read and for write, use schema optimized for updates
- Suits the systems that work with commands and maps the interactions of users
- Combine Command and Query Responsibility Segregation with domain driven design (DDD), appropriate for commands and event-oriented approach
- Domain Driven Design (DDD) has a unique identity defined by object and not its attributes
- Exceptional results can be achieved by adding event sourcing and DDD to CQRS while developing web and cloud applications
- Reduces latency and makes the response from requests more predictable
- Parallel access by multiple teams can help development if they know CRQS
- Manage the security, validations, and permissions with ease
- Keep strict control on which entities writes on the data
- Addresses concerns relating to the write model which has complex business logic compared to the read model
- Materialized view of the read database simplifies the queries
- Streamline the concurrency and locking of transactional databases and its management
- It enables event-based programming models
- Event sourcing pattern maintains audit trail and history of the transactional data
- Using integration events makes it easy to change the internal domain events
- One-way commands can be changed in the events of an event-sourced system
- Improve scalability by managing and accessing the data divided into partitions
A major difference in read and write services is about the features read services provide e.g., authentication, caching, encryption, limited retention, replication, elastic scaling, and sharding.
Questions you should ask while implementing CQRS:
- How are you treating commands/writes and are there any side-effects?
- What is the flow of handling the command?
- How are you planning to deal with the queries?
- How will you retrieve data from multiple services?
- Are you using a real-time database?
- How will you consolidate the data?
How to use Command and Query Responsibility Segregation (CQRS)?
- Different Object Role Modeling (ORM) can handle queries efficiently and writes powerfully
- Use event sourcing to gather the events in a database to know the current status of the command
- Never copy data to a separate database or messaging infrastructure
- Design a read-only replica of the database to support the queries
- Avoid duplication of data on the system, call API
- If you have a higher number of reads compared to writes, assign more resources to read services
- Applications that have too many users that access the system
- Let the write model treat the set of associated objects as a single unit, it becomes easy to store the changes in data
- Handle several large d/b, where only one of the user parties is allowed to update/change the database
Restrictions imposed by Command & Query Responsibility Segregation (CQRS):
- O/RM tools or scaffolding mechanisms cannot create the command and query responsibility segregation code automatically from a database schema
- When the resources are updated, it will queue all other read requests
- It is meant for large and complex applications that require higher scalability
- Keeping the databases in sync is a must if separate read-write databases are used
- During designing if the focus is on the availability of systems, it weakens the desired consistency between the read-write sides
- If you have multiple databases due care should be taken that read services handle only reads
- Bringing stability between read and write databases is a challenge
- CRUD (create, read, update, delete) does not update the read side thus cannot be combined with CQRS (Command and Query Responsibility Segregation)
- Calling API for the data can sometimes raise complexity levels, increases dependencies affecting service quality
- It’s not useful for applications based on simple business logic
- Event sourcing pattern can complicate the application design
- Use strings, numbers, lists instead of value objects
- Developers can change the definition of value objects, which can change the strategy or break the existing events
- Handling eventually consistent data is problematic
When to go for CQRS design pattern?
- The number of reads for the product/service is more compared to the writes
- If your service is based on fast-growing data
- The business requirements change frequently and you expect the system to evolve
- There are likely to be many versions of the model
- If scalability is one of your priorities
- If a queue of messages works for your system
- When multiple services modify the same resources
- If other applications read the data which you write
- Avoid or minimize conflicts caused by the parallel use of data by multiple users
- Complex processing of logic where users are directed through it
- The write model has several validations of input and relating to the business
- Command and Query Responsibility Segregation prevents failure of other subsystems if integration with other systems is combined with event sourcing
- Development is split two wherein developing complex domain for a write model and another team to focus on read model or UI
Best practices of CQRS:
- Use integration events between services and not the domain events
- Use simple value types not the value objects in domain events
- Refer data consistency primer to understand the issues you face in eventual consistency
- The data partitioning guidance explains about the best practices to divide data into partitions
- Messaging is commonly used to process commands and publish update events
- Event sourcing pattern improves performance and response rate
- Create materialized view with help of read model or can consist of a materialized view of a write model data
Put behind the negative impact on the performance caused by the load on the data store and data access layer. Command and Query Responsibility Segregation handles complex queries like an expert. Though CQRS is not for simple business logic, you can still apply it to sections of your application. The foremost advantage is that it sets you free from the worries of displaying data in an improper context.