From the beginning of my current project (13 years ago now, ignore the outdated tech components in this post!) we have been working under some horrible constraints, many imposed by legacy systems, many by late decisions that would have speeded things immensely if made earlier, and many imposed by decisions that are outside of my control.
This lead us early on to make decisions on architecture that eliminated any possibility of using DDD heavily, and as I mentioned in my original post about this project it is also essentially a glorified CRUD system — we read data from databases, we modify it a bit, and we put it back again.
What We Are Doing — Command Query Separation
The first architectural choice that I made, and in hindsight got accepted with relative ease, was to employ Command Query Separation (CQS) to simplify the system.
Previously I linked to one of my own blog posts here, but it is a little too far out of date. In summary Bertrand Meyer summarised a CQS method as:
“every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer”
In architecture terms CQS is about splitting your read code from your write code, one version of this being to split reporting data from transactional data
Earlier projects had suffered quite badly from being abstractions of legacy systems with new functionality bolted on. As far as possible I wanted to eliminate this problem from our project, as I was all too aware that this was an easy trap for the team to fall into, and would burn a lot of development time very fast.
To make the system simpler I chose to separate our query mechanisms from the “domain” type stuff, our commands and data writing/updating code.
CQS is a pretty simple concept. One path through your system is responsible for querying of anything much more than “Get By ID” type calls. This side of our system is responsible for reading data from legacy systems, reading data from legacy web services, and for reading data from our application database.