Wednesday, October 22, 2008

DDD and Complexity

There have been some interesting and entirely valid discussions on Twitter about the validity of DDD and about deciding when its useful and when its too complex (including good comments from Casey Charlton and Jimmy Bogard). I full agree with Casey and Jimmy and the comments, when combined with an interesting discussion on the topic at the latest ALT.NET UK discussion, let me wanting to blog about how I think DDD can be used in different types of projects.

First off I must admit that even for a simple business system I'd be thinking about using some of the patterns from DDD, in particular I think these usually have value:

  1. Aggregate
  2. Repository
  3. Service

For example I find that thinking about aggregates makes me think much more carefully about how to map those classes to the database, for example how far to cascade, which in my view is a good idea as not thinking about boundaries can lead you to some fairly annoying debugging sessions. You can take these three patterns and with a good ORM and create and map a simple domain model to a green fields database very quickly. 

Tradeoffs

Here's some of the tradeoffs we're making when using DDD on a system that it doesn't necessarily suit:

  1. Analysis/Design - We map completely skip the analysis/design and in particular the discussions with the domain expert, instead starting from our requirements and letting TDD and our own design skills guides us to the correct design.
  2. Encapsulation - We might expose everything using getters and setters and the domain may be anaemic, for example validation may be in attributes and/or use a custom framework.
  3. Design Clarity - If our primary focus is on getting going fast then we're going to have to cut some corners.  We'd bind the domain to the GUI, design it to be as easy to map to the database, make it easy to create domain objects (default constructors) and generally make tradeoffs in the quality of the domain model to make our own lives easier.
  4. Flexibility - A model that is quick to create/map/bind is not likely going to be flexible, this may or may not be a problem.
  5. Patterns - We're ignoring half the patterns in DDD, patterns that have a lot of value in a complex domain model but may not be justified when the domain is simpler/more closely bounded.

We make these tradeoffs to make our lives easier and in particular I wanted to cover two of the tradeoffs you may choose to make.

Design Clarity

If we want to be able to bind your GUI to the domain and map it to the database quickly then we can being to fray our domain model:

  1. Value objects make binding and displaying validation errors trickier.
  2. If our user interface uses wizards then the GUI will want to create domain objects early on in the wizard, possibly without giving us any meaningful data. We thus end up with default constructors or constructors with very few arguments.
  3. If we use an ORM with a unit of work it will probably fight against our need to validate aggregates before saving them.
  4. If we use an ORM we'll find it hard to version the entire aggregate.

With discipline you can make these tradeoffs whilst still maintaining a comprehensible model but there is no doubt that we are making tradeoffs.

Flexibility

We're also sacrificing flexibility, for example a lot of talk about repositories right now focuses on generic repositories. For example we'd have a Repository<T> class where T is an aggregate root and you'd have query methods on this repository that would take Linq specifications. That's going to be fine for a lot of cases but in more complex models (or where we don't control our environment fully) our repository can encapsulate complex logic, for example we should be able to ensure the following:

  1. Instances of aggregate are never deleted or they are simply archived.
  2. Instances of aggregate Y are built up from multiple data sources.
  3. Instead of mapping aggregate Z to a (legacy) DB we map some simple DTO's and then in the repository convert them to our nicely designed aggregate.
  4. Query Z is very expensive and needs to be done using SQL.

Those are all things I’ve had to be involved in when working with a moderately complex domain model and repositories helped encapsulate those details. So whilst I think generic repositories might have their place ins some systems I think you have to be aware of the choices your making.

What was the point of all this?

My point with all this is that you can get a lot of value from DDD without following it too closely, but you need to be aware of what tradeoffs your making and why. Choosing to go for a simple domain model when you have a complex problem to solve is a really bad choice and going from active record (true active record) to a real domain model is not going to be a smooth transition.

However I don't think the choice is easy, for example there's been a lot of discussion recently on whether DDD and complex models are suitable for CRUD related problems. In general I can see why using DDD on an average CRUD system is a mistake but sometimes it is worth using. For example we used DDD on a CRM system that among other things handled parties and their associations in a temporal manner. This was a complex modelling problem solved with a complex pattern but primarily we were handling CRUD (including constraints/validation) and setting the stage for other systems to use the information. Trying to do this using active record would, in my view, have been a big mistake.

So as Casey pointed out DDD is expensive and whilst it can pay off you need to do in with eyes open fully aware of the tradeoffs involved.

Share This - Digg It Save to del.icio.us Stumble It! Kick It DZone

6 comments:

  1. Anonymous9:23 pm

    Good post, I think my other point was that there is a cost to doing DDD, and there is a big payoff ... but the payoff only comes when you are using DDD to solve the right problem, too many problems people are trying to use DDD on won't benefit.

    As you point out, some of the practices and principles of DDD can be used in isolation and can all add value, going full out balls to the wall DDD is probably overkill for all but the most complex of problems

    ReplyDelete
  2. Anonymous9:53 pm

    I'm having a hard time understanding my own mixed reactions to this post. I agree with everything you've said, no question. The part that confuses me, though, is that I want to say that the implementation details don't matter as much as this post makes them out to matter. DDD is really bringing to language of the domain into every aspect of the system - through all of the different models and representations of that system. So while we have to keep everything you've said in mind, I don't think it really matters what your implementation of Repository is, at the DDD conceptual model level. that's an implementation detail, not a domain model concern.

    Does that even make sense? I'm not sure I can fully express my own thoughts on this, at this point.

    ReplyDelete
  3. @Derick
    Definitely what you say makes sense but I definitely think the design aspects still matter and are actually covered quite a lot in the book.

    In reality lots of choices you make don't really relate to the UL or to the domain experts, they're about the realities of writing software (Linq vs SQL, unidirectional vs bidirectional etc).

    And your right they're often implementation detail but if your code is your model then those implementation details matter. Otherwise even despite the best domain analysis the resulting model can end up being a mess.

    That's been my experience anyway.

    ReplyDelete
  4. Anonymous9:46 am

    Hey Colin,

    Good post on DDD ... I share the same feeling that still, today, even though they are more & more people knowing DDD, there still isn't any good tool / library that contains a set of minimum building blocks for DDD.

    We still have to build everything manually even though some DDD problems were solved with patterns, common OO constructs, ...

    As I said before in a post on my blog (http://blog.yoot.be/post/Working-on-a-Domain-Driven-Design-DSL.aspx), I think we need a DDD DSL that will cover most of the basic recurring aspects of DDD (defining entities, relations, value objects, aggregates, repositories, factories), while still keeping the generated code open enough for customizations.

    Also, such a framework could have a provider model supporting common ORM such as NHiberante, Linq2Sql, Entity Framework, ...

    Drop me an email if you're interested working on such thing ;o)

    ReplyDelete
  5. Anonymous2:26 pm

    @Colin

    "if your code is your model then those implementation details matter. Otherwise even despite the best domain analysis the resulting model can end up being a mess."

    very true. at some point, we do have to care about the implementation details - especially when we are looking at the code as a representation of the model.

    ReplyDelete
  6. Anonymous2:11 pm

    I think the main problem with small, simple applications is that they somehow tend to grow and attract new features quickly. Very easily such a system becomes a maintenance nightmare.

    Having a baseline architecture like described is great, because it has all the essentials and let's you easily refactor to full DDD.

    ReplyDelete