Monday, April 12, 2010

Three types of services in Domain-Driven Design

I've been re-reading Domain-Driven Design [Evans]. My first reading was in 2006 when I'd just started using Hibernate/NHibernate. In the years since then I've done several projects using a domain, a repository, and tests to validate the domain.

In re-reading the book, I'm seeing that Evans spoke about 3 types of classes in the domain:
  • Entites
  • Value Objects
  • [Domain] Services
In the projects I had done, I used only the first of these, Entities:
  • Every class had a PK-mapped identity from the db.
  • I had not used the Value Object abstraction to group attributes using composition (eg. Person.Address).
  • My use of services had been limited to services outside the domain (application and infrastructure, defined below.) As a consequence, I had observed a design issue in my domain entities: even though though they had thorough test coverage, the entities had become large, with many methods. As a result, the tests that ran against these entities by definition had to be coarse grained, often testing logic nested several levels deep within the entity..
Last fall, I revisited the book Refactoring [Fowler], and recognized that the use of delegation (Extract Class, Strategy, and others) would help to move a lot of the logic out of my entity classes into abstractions devoted to particular parts of the business logic. Among many benefits of this, tests could now be written directly against these abstractions. However, my concern was WHERE these extracted non-entity classes should go. Would they clutter up the domain? Should I create a separate namespace specifically for these classes?

With this question in the back of my mind, Evans explanation of Domain Service classes made perfect sense. They belong inside the domain and serve the entities as useful abstractions in their own right. And they are not to be confused with either:
  • Application services (eg. the controller in MVC, or a web method); or
  • Infrastructure services (eg. adapters on calls to external infrastructure outside the application.)
The following graphic is my attempt to crystallize my understanding of the 3 distinct types of services for future reference. I've highlighted the different services in each layer.

2 comments:

Anonymous said...

I like to think of it like this a entity is very simple object with only helper methods e.g. Order (I guess these are value objects had to say for sure)

public Order
{
public int Id {get;set;}
public List OrderItems {get;set;}
public int OrderTotal
{
get{ return OrderItems.Sum(oi => oi.Cost); }
}
}

A service is something that operates against the domain entity and or dbase

public OrderService : IOrderService
{
public Order AddItemToOrder(NewOrderItem item)
{
//Do all the wok here....

}
}

NewOrderItem is only a message class thats passed into the OrderService....

This keeps the Order Entity small and uncluttered and you can split the service how ever you want... The external systems only wok with the entities and the IOrderSevice you can then implement Strategy etc bhind the interface. I prefer to slit the domain service actions e.g. AddItemToOrder into their own classes and test them the rest of the code is really just composition.

Anonymous said...

I was very pleased to find this site.I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.
domain and hosting services india