Monday, June 18, 2007

Domain Classes should not be passed to UI layer.

Debasish Ghosh, one of my favourite bloggers, posted an entry titled
Domain Classes or Interfaces? last October. Later he posted a follow-up entry Abstract Classes or Aspect-Powered Interfaces?.

He had this great debate with Sergio Bossa in the mailing list of Domain Driven Design (DDD).

I was surprised to read that both Debasish and Sergio are in favour of passing domain objects to the UI layer and using them as command objects, in the context of DDD discussion, because this kind of usage is code smell of Anaemic Domain Model.

As I understand, one major reason cited by Debasish to use abstract domain classes is to maintain the integrity of domain objects, making sure no constraints are violated.

However, when a domain class is designed following the philosophy of DDD, there are typically few setter methods, making them unsuitable to be used as a command object in the UI layer.

Moreover, there are typically some business methods that you would not like to be exposed to the UI layer, such as those that access database and must be wrapped in a transaction, making it even more undesirable to pass domain objects to the UI layer.

In my opinion, a domain class typically has three interfaces (not necessarily Java interfaces):
* Business interface - these method usually bear domain-specific meaning in their names.
* State Exposure interface - typically getter methods
* State Manipulation interface - these methods update the object state without violating any constraints, and are usually named updateXXX instead of setter.

Business interface should not be exposed to UI layer. If the return value of any of the business methods are to be displayed in a UI, a getter method should be defined in the State Exposure interface, which should then delegate to the business method.

State Exposure interface is usually passed to UI layer for display. In a proper application design, the role to expose domain object states is usually assumed by a Data Transfer Object (DTO). In a Spring+Hibernate application, this Java interface can be implemented by the domain class directly, and the domain objects can be passed to the UI layer without exposing business methods. Typically, Open Session In View (OSIV) is required in this usage.

Even if the domain class implements the State Exposure interface , the domain objects that are passed to the UI layer should not be used as command objects. Each piece of update should be invoked on a facade, which then invokes methods defined in the State Manipulation interface. The piece of information for update is usually passed in as a DTO.

Note that there is difference between the DTO for state exposure and the DTO for state manipulation:
The DTO for state exposure usually captures most, if not all, state of the domain object.
The DTO for state manipulation usually captures only the piece of state that is being updated.

In conclusion, because of the three interfaces a domain object usually has, it is strongly discouraged to pass domain objects to UI layer or use them as command objects, when applying DDD.

1 comment:

Unknown said...

re: [However, when a domain class is designed following the philosophy of DDD, there are typically few setter methods, making them unsuitable to be used as a command object in the UI layer.]
The technique that I use is to expose the setters to the MVC framework only (e.g. for Spring MVC command objects) and restrict the setters to the other layers using aspects. And setters will be in the implementation class of the domain object only, which anyway should not be used by the other layers of the application.
e.g.
interface Employee {
//..
}

class EmployeeImpl implements Employee {
//..
void setName(..) {}
void setAddress(..) {}
//..
}

In the above code snippet, *all* layers of the application will use Employee interface (or if we go for abstract base class, a similar abstraction). *Only* the MVC framework can be given access to the implementation, so that it can use the setters. This can be enforced using aspects.

This approach promotes use of domain abstractions much more and at the same time gets rid of additional DTO like stuff which need to be created for data transportation across layers only.