Wednesday, October 24, 2007

Anemic Entities - Fallouts of an EJB era ?

When I first started working with EJB's the 1.0 and 1.1 versions, there were two types of enterprise beans

  1. Session Beans
  2. Entity Beans

We were all taught to put business logic into session beans and persist them using entity beans. No business logic was present in entity beans and it generally had only getters/setters. The only reason we were encouraged to put business logic in entities was to get performance gain - EJB tips.

According to OO principles the definition of a class states that a class should contain both structure and behaviour. And we ended up violating this first principle of OO by splitting our structure(entity/vo) and behaviour(model/services) into 2 separate layers (because of our tools ??). This anti-pattern has been termed as Anemic Domain Model by Martin Fowler.

This influence sort of carried on with most of the people. Even after EJB's lost the appeal and with IOC/ORM tools gaining popularity, people still architected systems where entities/value-objects/dto were a layer of objects having just get/set methods. These objects were read from DB using DAO's and sent to model/services layer where all business processing happened.

To be fair to people, the IOC containers of the day did not support DI'ing objects read from DB using tools like hibernate. With such excuses, we lived on writing more procedural style code with OO languages.

Now Spring 2.x has started supporting dependency injection on objects whose life cycle is outside its control. Using the @Configurable annotation Hibernate can create entity/dto objects from database and spring configures these objects a normal bean and wires up the dependencies.

Some more info regarding this can be found here and here.

To me creating an architecture where i can tell the domain object to go take of certain things leads to a very powerful api and also the system is easy to understand.

For e.g. I would like to do things like the following in my api's.

  • order.ship() instead of shippingService.ship(order)
  • movieRental.calculateLateFees() instead of feeService.getLateFees(Rental)

Coupled with a FluentInterface, I think this should be the future of enterprise apps (well atleast till erlang/haskell become more mainstream). This would make systems more easy to maintain and cleaner.

I did not make the relationship between the anemic-domain-like-design to EJB's till i proposed to a co-worker on adding more domain logic into the entities, the first response was

"This looks good, but should'nt we have all business logic in separate classes like how we did it using session beans"

And then it stuck me, things are not about to change for a long while !

Subscribe to comments for this post

3 comments:

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

I disagree that an Anemic Entity is an anti pattern.

Objects may contain data and behaviour - do helper classes have to contain data? Do entities have to containt methods?

There are numerous examples one can list where a canonical lightweight, portable, type safe object that maybe serialized / transmitted, etc, etc. is desirable.

If one built a 3 tier system and the middleware cache were to receive a Customer entity, would it make sense to invoke customer.Save() ? Would it make sense to invoke apple.Eat() on an Apple entity?

The systems and software architect will often find themselves in the situation where a canonical entity has to be provided to some business transaction. The business transaction should perform the operation (method) on the entity (data).

In enterprise and distributed systems, one would compose cacheManager.Save(Customer) rather than apple.Eat()

Kaushik said...

@Anonymous, I am not saying apple.eat makes sense as the apple cannot determine how its eaten. Think of it like this, the apple should know what should happen to it when someone bites into it. So apple should determine what should happen to it when a force is applied to it, what juices to release etc.

Person.eat(apple) doing all above means that person knows about internal state of apple too much.

 
Clicky Web Analytics