We Are Not Doing DDD – Part Two - CQS

From the beginning of my current project 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 CQS to simplify the system.

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.

Querying

The Query side deals largely in DataTables, DataSets and a very very limited number of DTOs. This data is largely and essentially used for display purposes, it is the contents of search results, the results of postcode lookups, the information to populate dropdown lists and tables.

The Query side of CQS does not need strongly typed entities, nor does it require strongly typed DTOs - as it is largely ad-hoc data maintaining these entities and DTOs would consume a disproportionate amount of development time for something a DataTable can deal with more than adequately.

Our Query side actually uses the Query Object pattern, most of which encapsulate a call to an Oracle DB, some of which wrap simple NHibernate criteria and a few of which sit around web services. These are fronted by a WCF facade, which allows us to put these queries out of process, and to cache them aggressively should be need.

What we do not have in the system anywhere, and especially in the Query side, is any big entity model – we have two very small entity models (5 entities in total) used for very specific functions within our application.

Command

The Command side of the CQS equation is a little different. Firstly, it deals with anything that is essentially a request to "go do something". In our case these are commands like "SaveDraft" and "CancelPolicy"

The Command side can write data to the databases, the Query side is not allowed to.

If we were doing DDD, this is where our Domain would sit - and in fact we have been referring to this as "the domain" for most of this project. But, we aren’t using DDD and we don't really have a Domain Model. It is however where most stuff we could describe as "logic" lives. This is primarily a bunch of application services, most of which operate in response to messages fired over MSMQ using NServiceBus.

This side of the architecture has a number of listeners that are responsible for pulling messages from various MSMQs and for dealing with the specific requests, for example pushing data back to our legacy systems, for logging, and eventually for notifications.

Benefits

Early on, the use of CQS paid for itself easily. By removing the complications of maintaining read and write models together, we quickly managed to get working prototype up and running, with no need for a "domain" or entity model up front.

As the project has progressed, this decision has helped simplify decisions that otherwise would have involved structural or fundamental changes to the architecture – but more importantly, it has helped all of the developers think in terms of a command driven system, rather than viewing the system as CRUD over a database.


Posted 06-22-2009 5:32 PM by Jak Charlton
Filed under: , ,

[Advertisement]

Comments

Markuas Zywitza wrote re: We Are Not Doing DDD – Part Two - CQS
on 06-23-2009 5:30 AM

Jak, in the Query you say that there are no DTOs or strongly types entities for querying, yet you mention NHibernate Criteria queries.

Now, do use an object model mapped by NH for querying or plain SQL/System.Data.XXX or both?

Jak Charlton wrote re: We Are Not Doing DDD – Part Two - CQS
on 06-23-2009 6:08 AM

We use NHibernate for a very limited part of the query side, and we have a single DTO to return results from that query.  Creating a DataTable from the result of the NH query here would be a pointless exercise.

Everything else returns a DataSet/DataTable - and largely comes from Oracle SQL / ADO.NET

JDR wrote re: We Are Not Doing DDD – Part Two - CQS
on 08-17-2009 10:12 AM

Enjoyed this specific example and you blog.  I am faced with a similar situation but cannot use nHibernate as the datamodel is too free form and unstructured for 'extensibility' so the tables are overloaded and no meaning can be inferred.  Additionally, much of the domain data is in realtime systems accessible through a variety of web services only.

Do you know any framework that can aggregate data for Domain Model Entities across multiple non DB datasources?  Thanks again.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)