There has been some confusion recently around a recent evolution of DDD, the idea of Command Query Separation (CQS) at the architectural level.
This post is yet again jumping ahead into the “advanced” stuff, so go ahead and skip this if you just want to get the basics down first… those will come soon I promise.
Many of you will be familiar with CQS in it’s original form, Bertrand Meyer presented it 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”
On the method level it is an excellent principle to follow, but Greg Young introduced (at least I heard it from him first) the idea of Command Query Separation at the architectural level. This was also discussed a long time back by such luminaries as Eric Evans and Martin Fowler.
What Does CQS Mean at an Architectural Level
In DDD, as presented by Eric Evans originally, the Repository concept is responsible for abstracting your Entities and Value Objects away from the way they are persisted. To retrieve an Entity, or a set of Entities, you would use a Repository method like .GetAllOutstandingInvoices or pass a Specification into a generic query method.
This is a perfectly viable and valid way of querying your Entities, but it does have some issues around some aspects of an application, these are generally referred to as Reporting issues. Reporting issues may well be reports in the classic database style, or may be such things as user interfaces that require searching, sorting, paging and filtering of data.
The concept of applying CQS at an architectural level says, our Domain and transactional operations will use the Repositories, but for Reporting operations, we will use a separate mechanism. The Command is the Domain operations, the Query is the Reporting operations.
Does This Mean We Have More Than One Set of Data?
Perhaps. For the vast majority of systems this shouldn’t be an issue, whatever sits behind the Repositories can also provide the data for the Reporting side of things. This after all is just an issue of Bounded Context again – we have a separate Bounded Context for Reporting, and as Bounded Contexts have their own code and data access, this Context can encapsulate all read requests, and just read them off the same store that your Repositories in your main Domain do.
For example, your main Domain may be using an ORM like NHibernate sitting behind your Repositories. It will provide a rich mapping from your Entities into the database behind.
Your Reporting Context may well use NHibernate too, but with a simplified model designed for read purposes, or you may even just have an ADO DataReader sitting in the Reporting Context, reading directly from the database that NHibernate is writing to elsewhere.
It is certainly viable to have more than one persistence mechanism however and larger more complex systems may well duplicate data. I can almost hear a bunch of you shouting “Heresy!”.
Duplication of Data
“We spend a great deal of effort maintaining data, maintaining integrity, maintaining consistency, and some fool wants to duplicate this problem all over, now we have two lots of data to manage and synchronise!”
Well, no. When you think about it, this is just data for read purposes. And that means that this data can be a subset or a combination of data from our Domain. It could be created by events being published from the Domain, or it could be created by taking a snapshot of the Domain data.
The only issue that really exists is that this data could be stale or inconsistent – it may be 5 seconds out of date, or 10 seconds, or maybe just 1 second – but this data may not be up to date.
Well, of course it may not be up to date… but is any of the data in your system really up to date? Even if you just requested it from your Domain, and it appeared on screen, before you hit any key on your keyboard, that data is already stale – by the time you press “update” someone or something else may have modified the data.
Eventually the data may be up to date and consistent, it just may not be the instant you request it.
So yes, the data may be stale, but is that really an issue? (hint: the answer is no)
It may pay to split your Reporting concerns from your Domain concerns, keeping your Domain clear of ad-hoc reporting concerns, and UI concerns. It may also be far more effort than it is worth if the system does not have either massive numbers of these kinds of queries, or just is not that complex.
However, bear in mind that this is a good option for allowing the Domain to evolve without concerns from other parts of the wider application leaking into it, and is a good tool to have ready when you face this issue.
1) Domain Driven Design: A Step by Step Guide
2) DDD: The Ubiquitous Language
3) DDD: Bounded Contexts
4) DDD: There Is No Database
InfoQ Free eBook : Domain Driven Design Quickly
Domain-Driven Design: Tackling Complexity in the Heart of Software (Eric Evans)
Martin Fowler’s Version: EagerReadDerivation
del.icio.us Tags: DDD,Domain Driven Design,Practices and Principles
02-12-2009 4:40 PM