CQRS is a Command, Query, Responsibility and Segregation design pattern.
CQRS (Command Query Responsibility Segregation) is a powerful architectural pattern that seems to cause quite a lot of confusion; it breaks from the norms most developers cling to by segregating the read and write operations with interfaces (check out SOLID to see how this improves performance, connections, and maintenance). With the popularity of micro-services and the event-based programming model, it is important to know what CQRS is. This is a potentially good option for working with large complicated databases.
First, let’s make sure we are in agreement on what CRUD (Create, Read, Update and Delete), the old CQRS competitor, is. When one thinks about this, CRUD is what most basic software systems rely on. A developer has some records, they may want to read some records, update the records, create a new record or delete some records. If one wants to build a system, a reasonable starting point would be using the same model for retrieving object as well as updating objects. As an example, assume you want to write a “Video Store Application”. You may have a VideoInventoryService that lets you do things such as add new videos to the inventory, mark some of the videos as loaned out, check if there is a specific video, etc. That would be a very simple CRUD system.
Letter | Name | Description |
---|---|---|
C | Command | A Command is a method that performs an action. These would be like the Create, Update and Delete parts of a CRUD system. |
Q | Query | A Query is a method that returns Data to the caller without modifying the records stored. This is the Read part of a CRUD system. |
R | Responsibility | The Responsibility part here is about providing a responsibility for the Command part and and another responsibility for the Query part of the CQRS system. |
S | Segregation | Segregation is the explicit separation of those Command and Query responsibilities improving performance and maintenance. |
In CQRS the goal is to segregate the responsibilities for executing commands and queries. This simply means that in a CQRS system, there would be no place for VideoInventoryService that is responsible for both queries and commands. You could have VideoInventoryReadService, VideoLendingReadService and maybe more. These services are broken down into separate responsibilities without concern for the other services. They will even run simultaneously meaning the micro-services don’t have to wait for a write or a read to finish. That is the job of the appropriate micro-service to finish it’s task while allowing others to continue.
From a desktop development world, or maybe even the monolithic services view, this does not sound like the most practical thing. And in some cases it may not be practical. How complex is your data source? Will breaking it down make development and maintenance easier?
Another aspect to keep in mind is that if the developers are employing an actual domain driven development practice then the CQRS system is made even more simple by only being concerned with it’s own specific domain. The purposes of the data driven micro-services become more simplified and the micro-services themselves no longer have to be concerned about details outside of their domain. Also, another nice thing about CQRS is there is no requirement for Event Sourcing. Commands are in effect streams of events that are persisted in the command part of the CQRS system. Queries only see and interpret these events once the data source is updated; no early peeks or corrupted data. In an event-driver distributed system like that seen in services or desktop applications there must be constant messages being passed around to keep changes orchestrated. Using the same domain model, or not separating these responsibilities, would be a mistake.
Finally, in summary, for most non-trivial systems it is not necessary to implement CQRS. In micro-services, the CRUD system is fine when the system’s purpose is very focused on a common task like instant messaging, creating a meme repository or maybe having a driving app. Adding complexity like a mirrade of unrelated tasks, a complex multi-purpose database, or other trivial complications makes CRUD more difficult. The added complexity may end up detrimental to the system design. Plan carefully and be ready for the future.