Transitory Domain Objects

Saturday, May 30th, 2009 by Sebastian Markbåge

A common problem with DDD is the injection of services to your domain model. Sometimes your domain relies on external services to do it’s job. You could do that by injecting your services directly to your entities using NHibernate Interceptors or ObjectStateManager for Entity Framework v4.

There are many design issues with the POCOness of Entities when you keep references to external services within the Entities themselves. The reference itself is (usually) infrastructure and not really a persistence concern.

Double Dispatch, Specifications and Services

The double dispatch pattern seems to be a popular approach. A better solution seem to be to move the logic in front of the Entites. Usually people seem to solve this by moving logic to services or even specifications.

Moving domain logic to services is a big no, no. That’s a gateway to anemic domain models and bloated service implementations. Services should be a last resort for external concerns and should probably have a solid anti-corruption layer.

The double dispatch pattern is a pain, ugly and introduces lots of references to services where the ubiquitous language doesn’t dictate it.

The specification pattern is particularly ugly because that’s (usually) not how a domain expert would refer to the issue. We are violating the ubiquitous language.

Transitory Domain Objects

Recently I’ve started introducing unpersisted classes to my domain models. If you think about it, many domain models have transitory terms and concerns that are not really persisted.

Imagine that your domain model consists of an archive of home photography. Let’s call them Photos. Now, you want to work with a couple of them. You pick out all the ones that have a red lavish hue and start organizing, labeling them or other operations. Now you have a set of Photos.

You could claim that it is a UI or Controller concern. Given the right bounded context, that set of photos IS A Domain Concern! Your domain could have domain specific restrictions and operations occurring on those sets of photos. You can think about them as a workspace or extended units of work.

Now this set isn’t persisted. It’s not an entity, it’s not a value object. Your entities can’t refer to it. This transitory logic lies infront of your entities. Since it’s transitory it also means that it can contain references to repositories and external services. It makes reference management much easier.

Now we can change out our specification and double dispatch patterns:

var redishPhotoList = photoRepository.Find(
  new HueSpecificiation(colorDetectorService, Color.Red)
);
foreach(var photo in redishPhotoList){
  //checks...
  photo.MarkWithMetaData("RED", metaDataService);
  //contraints...
}

To something more domain specific:

var photoSet = new PhotoSet(photoRepository, colorDetectorService, metaDataService);
photoSet.UsingOnly(Color.Red).MarkWithMetaData("RED");

We now have a domain object that we can easily pass around our application.

When you think about it you’re probably already using this pattern either as helpers or as “services”. But making the clear distinction that this is 1) A Domain Concern. 2) Temporary. Makes it easier to place your logic and apply constraints.

Achieving pure POCO is a pain from an infrastructure perspective but it’s worth it once it’s in place. I should be able to pass it to and from Db4O without any infrastructure concerns. Then you have a clear and solid domain model.

5 Responses to “Transitory Domain Objects”

  1. Roger Alsing Says:

    I’ve got a few remarks on this one:

    >>The reference itself is (usually) infrastructure and not really a persistence concern.

    Entities are not supposed to deal with persistence concerns, they are supposed to deal with _domain_ concerns.
    The entire point of POCO is not have persistence concerns in the entities.

    I do agree that keeping service references are an infrastructure concern, and should if possible be abstracted away.
    In the easiest case it can be done by simply require the consumer to pass the reference into a method instead.
    e.g. order.CalculateTotals(_someTaxCalculatorService_);

    There are also other means to reach separation of concerns, eg AOP or introducing transient entities that operate over other entitie as you describe here.

    >> Moving domain logic to services is a big no, no. That’s a gateway to anemic domain models

    That is not completely true, “domain services” are apart of the domain itself, and have a very clear role in the domain.
    They keep functionallity that does not fit into an entity (persistent or transient) by the simple fact that it is an operation that is not associated with any sort of identity (persistent id or transient pointer/ref)
    but is rather operating over a set of different entities.

    I do however agree that moving functionallity that does belong in an entity is a big no no.

  2. Sebastian Markbåge Says:

    >> In the easiest case it can be done by simply require the consumer to pass the reference into a method instead.

    Yea, this is typically using double dispatch.

    >> That is not completely true, “domain services” are apart of the domain itself, and have a very clear role in the domain.

    Services is such an overused term and it’s unclear when to use it. Services in DDD are too undefined and can span various concepts. Thus violating single responsibility.

    “Domain services” is close to what I’m doing but I’m using a slightly definition and different constraints to put it more in line with the UL and ensure separation of concerns.

    I don’t couple any external operations to my transient domain objects. They are side-effect free, as Haskell people would call it. Therefore I don’t use an interface and I don’t bother with IoC because they contain only side-effect free domain logic.

  3. Sebastian Markbåge Says:

    >> >>The reference itself is (usually) infrastructure and not really a persistence concern.
    >> Entities are not supposed to deal with persistence concerns, they are supposed to deal with _domain_ concerns.
    >> The entire point of POCO is not have persistence concerns in the entities.

    Yea, what I meant to say was that it isn’t a persistent concern within the domain. Even if that persistence is only in memory. A property of an entity is persistent as opposed to a temporary variable in a method. (Suggestions for better verbiage are welcome.)

    Service references are a transient concern during a certain operation only. I.e. infrastructure.

  4. Roger Alsing Says:

    IMO, what you are doing is Domain Services with an Internal DSL API.

    I do like the look of that API.
    But it would be possible to make it as a pure old domain service too:

    var photoService = new PhotoService();
    photoService.MarkWithMetadata( photoRepository , colorDetectorService, metaDataService, Color.Red, “RED”);

    Or if you use a container of some sort to configure your service instances.

    var photoService = foo.Get();
    photoService.MarkWithMetadata( Color.Red, “RED”);

    But I do like the fluent interface / internal DSL approach you have.
    The thing that bothers me about it though is that “PhotoSet” is probably ambigious semantics with what you get from a photo repository.

    You do get sets of photos from photo repositories.
    (most likely some IList (ignoring the fact that ilist is not a true set interface))

    Thus it would blur the meaning of a “photo set”
    Unless you explicitly starts talking about Photo Sets and Collections of Photos.

  5. Sebastian Markbåge Says:

    The problem with both those approaches is that I can’t easily do the filtering of Red hue in one place and marking them with meta data in another place. By introducing a transient workflow concept to the domain, I can move the concept around within my domain logic as well as in my application.

    myController.Photos = photoSet.UsingOnly(Color.Red);

    public IEnumerable List()
    {
    return myController.Photos;
    }

    public void Apply(string text)
    {
    return myController.Photos.MarkWithMetadata(text);
    }

    Granted, this is a too simplistic example as always with DDD. But you can see that as this gets more complex I’d have to pass around references to repository and services and/or specifications (Color.Red).

    In this case “PhotoSet” is a domain specific term which is why I went with that. Even though Set is also a technical term I favored the ubiquitous language. I’ve also had the terms Collection and List in my domains. Imagine a fashion designer’s “collection” or a customer “list” with own domain properties.

    It’s not my place to dictate the UL of the domain.

Leave a Reply