The story is a part of the series about software architecture powered by command-query separation principle and aspect-oriented programming.
Introduction and motivation
Reading through discussion threads about CQRS pattern, I often get the feeling that the general impression about the topic could be summarized into the following:
The whole concept seems pretty reasonable, and the idea behind it solid, but it looks like overkill for non-enterprise projects, I’d rather stick to…
Although I do understand such reasoning, I still think that initial skepticism is rooted in the fact that there is no clear way of taking advantage of a higher abstraction which sits behind the pattern. It simply feels that the implementation effort is too great and doesn’t pay off in “smaller” code bases. However, I strongly disagree with that.
Particularly, I think the size of a project shouldn’t be a determining factor to choose a certain approach, but rather its domain flexibility and compatibility. While it’s pretty much clear that there is no single architectural pattern (principle, abstraction) which would perfectly fit any domain, in a plethora of cases, CQS principle could be adapted and fairly successfully applied.
At first, I was suspicious to use the pattern in a production world, especially since the Domain model or classical N-layered approaches felt much closer and overall friendlier.
At that time, I simply didn’t know that Command and Query Separation principle, as an abstraction, could be modeled quite powerfully. The whole concept could be represented using a few interfaces in C#, for example :
Examining such model, thoroughly described in the Meanwhile… on the command/query side of my architecture posts, Chapter 10 of the Dependency Injection Principles, Practices, and Patterns book and others, it quickly becomes apparent how adaptable and flexible it is. In addition, carefully designed interfaces restrict the developer from abusing such a general principle and give core building blocks to accomplish greater and more complex architectures.
Developers have all the freedom to tailor a software solution to its domain’s needs. Practically, no other factors dictate that it must be a fully-fledged CQRS solution with distributed persistence stores and messaging bus in between. Therefore, there is no single reason not to (try) to apply a CQS principle in a project which is not of “enterprise” size, once the concept becomes clear enough.
It’s obvious that the implementation complexity of a certain theoretical pattern is influenced by the developer. When needed it’s acceptable to do a trade-off between the purity of theoretical concept and practical implementation. Especially, if it would enhance maintainability and reduce the overall complexity of the code base.
The whole series will be focused on showing and exploring practical implementation of CQS principle, built around a generic model which doesn’t fully follow the theoretical concept. The most surprising thing is that you could be perfectly fine if the Command returns a result, however under certain rules and discipline.
Many topics will be addressed along the way. Essential parts first — to get a general understanding of the approach, and then, gradually, other building blocks will be incorporated into the whole picture.
Series should act as a hands-on guide to the world of commands and queries. Starting from the base model introduction and later extending it with many cross-cutting aspects, molding it into a data processing pipeline.
The goal is to understand how to assemble a typical API server using the following building blocks:
Command and Query
Cross-cutting Aspects
Pipeline and Context
Messaging and Eventing
For each concept, feasible models will be presented and described, including their pros and cons. Even though the implementation is usually opinionated, I’ll try to keep the spotlight on the parts which are more or less universal and only explain important details of the underlying technologies and/or libraries.
Ultimately, the whole code base should adhere to SOLID principles practically out of the box which again leads to many great things like modularity, maintainability, reusability and many more.
In the next chapter Command and Query’s abstraction will be examined and the base model described, on top of which other parts will be built.
All the gists, examples, or solutions will be done in C# using the latest .Net Core/Standard versions and hosted on Github.
Top comments (0)