How the CQRS pattern changed how I think about domain modeling: part 1
What is command-query responsibility segregation and why does it matter?
Command-query responsibility segregation (CQRS) can be reduced to explicitly separating the discussion, design, and implementation of state-changing operations from information retrieval operations.
This segregation exists in nearly all Web applications where content can be created and viewed. Content is typically created on a Web page with forms supporting a particular workflow. Content is viewed on a different page designed for optimal presentation.
Why are the commands and queries segregated? This is because they are serving two different audiences or use cases, have different consumption patterns, and have different scaling needs (e.g. many more readers than writers).
What I am doing right now is writing some content which will then later be displayed (when you read it). My concerns for editing are different than yours for viewing. In fact, as a reader, there tends to be much more supplementary information on the page than there is for me the author.
Image courtesy of Eleven Labs
The image above may be helpful to show the separate paths even in the case for a single user. The mechanism for communicating state changes to the read model is not important right now, just that the decoupling of these two concerns make sense.
But it’s simpler
Although frontend design and development are in a fairly good state from this segregation standpoint, CQRS is often overlooked on the “backend” where the commands and queries are ultimately handled.
Speaking from experience, backend developers tend to generalize the data model and domain logic to support all commands and queries. My reflection and speculation as to why suggests its because we try to optimize for the simplest solution and minimal code. Since the “backend” is not visible to end-users, we can get away with this. However, the effects of the backend decisions manifest to end-users in indirect ways such as adapting to new requirements quickly and performance degradation.
Conceptually, one unified model is much easier to design and implement than two or more distinct models. One of anything is easier than multiple of something. However, the oversight is the fact that the requirements for the command and query models will continue to evolve and diverge as time goes on. These new requirements are learned and not apparent in the first few iterations.
Designing with the intent to have a unified model is a big mistake. Being naive to it is a concern (which is a motivation for this post). However, taking on technical debt and choosing to create a single model knowing it will diverge is OK if it is significantly easier for you or your team to get something working.
Designing for multiple models
With this background, in the next post, I will describe how to think about multiple models, how this changes interactions with domain experts, and the impact on you or your team’s work.