Objectopia

Non-anaemic models and service oriented architectures

Posted by Chris Burnley on May 20, 2009

The term “anaemic domain model” is used to describe an entity layer that contains very little business logic. Typically in this architecture, the business logic is contained in services and/or delegates. There are several problems with this approach:

  • Business logic quickly gets scattered and duplicated across the system
  • It is difficult to maintain because it is hard to determine which class needs to be changed
  • It is difficult to test because the service/delegate usually has many dependencies
  • It is not particularly object oriented (e.g. polymorphism, which can reduce a lot of complexity by reducing ‘type-logic’, is rare)

The trend these days is towards Domain Driven Design (DDD), and is a strategy against anaemic domain models. In this architecture, services are used as an ‘anti-corruption-layer’ to translate requests from the external domain to the internal domain of the system. The majority of the logic is contained within the domain model (this includes persistent and non-persistent objects).

When developing a non-anaemic model (e.g. DDD), it is tempting to call services directly to perform logic (to perhaps an external system, or send a message), to hide complexity from the client:

class Account {
    Balance getBalance() {
        for(Transaction t : getTransactionService().getTransactions(…)){
            //… sum them up
        }
    }

    TransactionService getTransactionService() {
        // lookup service
    }
}

I think this not good design for a number of reasons:

  • The risk of Leaky Abstraction (e.g. having to declare checked Exceptions to methods)
  • Generally speaking, the domain model doesn’t have enough information about the nature of the method call to perform well. The service would be better suited to know how the model will be used (e.g. in a loop).
  • It is harder to test the business logic because you’ve got to mock out too many dependencies.
  • I believe that entities should be deterministic, the behaviour must be determinable given the state of the system/database.
  • Potentially introduces circular dependencies between service->model->service->model etc. which causes problems for maintainability, testing and debugging.

So how do we have a nice, clean, rich domain model ? One way is to pass an implementation of an interface to the domain (e.g. a delegate to a service) so the domain can perform its logic:

class Account {
    Balance getBalance(TransactionRepository repos) {
        // … get the transactions, sum them up
    }
}
// Getting the balance on a single account
Account account =...;
account.getBalance(singleAccountTransactionRepository);
// Getting the balance on many accounts
List<Account> accounts = ...;
for(Account account : accounts){
          account.getBalance(allAccountTransactionRepository);
}

The idea here is that you substitute the most appropriate implementation to get the best performance for the particular use case.

There is a subtle difference between the two, but the second IMO is a cleaner, more-flexible solution.

One Response to “Non-anaemic models and service oriented architectures”

  1. [...] @PostPersist in the bean itself but that that would go against leaky abstraction (see post Non-anaemic models). Anywho it was pretty simple to get this working all that I had to use were a couple of [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.