Sunday, June 24, 2007

Is using domain entities in presentation layer encouraged?

There is an interesting discussion going on in the Spring support forum about using Hibernate entities in web layer.

In his reply, Debasish said:
I am all for using domain entities in the presentation layer. If you read the Expert Spring MVC book or the Hibernate book, both of them encourage using smart domain models and reusing domain objects in the presentation layer. The Spring MVC book recommends using domain objects as command objects and the Hibernate book recommends doing away with the behaviorless JSF backing beans in favor of smart POJOs in SEAM.
I have plenty of respects for Debasish. However, I have to disagree on this.

One thing that I have kept in mind is that Spring MVC and Hibernate's development started in the dark age of EJB 2.0, which forced developers to build enterprise applications with anaemic domain models using transaction scripts. At that time, many people equalled Java Beans to POJOs and domain classes. Unfortunately that was misleading... In a rich domain model, typically entity classes are NOT Java beans, because providing setter methods can easily break invariants of a domain class. Since then, Domain Driven Design has gained wider adoption and recognition.

In a recent presentation "Are We There Yet?", Rod Johnson, the founder of Spring, asked the attendees a question: when working with Hibernate, who use property access and who use field access? Those who use property access are persisting DTOs, or, using an anaemic domain model. I cannot recall the exact words, but that's basically what he said and meant.

I would like to add: that those who use domain classes as command objects in the web layer are working with an anaemic domain model.

For example, in one of the projects I have worked on, there is a Fraud class, which has three fields: fraudPaymentDate, fraudPaymentAmount, amountRecovered and dateRecovered. The invariants regarding these three fields are:
1) amountRecovered must not exceed fraudPaymentAmount.
2) When amountRecovered is $0.00, dateRecovered must be null.
3) When amount Recovered is greater than $0.00, dateRecovered must be present, in the past and must not predate fraudPaymentDate.

If this class provides setter methods for all these fields and is directly used as a command object, there is no way not to break invariants in the binding phase of Spring MVC:
If setAmountRecovered() is invoked with a non-zero amount before setDateRecovered(), then invariant no. 3 is broken.
If setDateRecovered() is invoked before setAmountRecovered(), then invariant no. 2 is broken.

Therefore, a command object typically does not maintain data integrity. Usually a validate() method is provided to the client to ensure data integrity AFTER the binding.

There is one big drawback with using validate() method: the domain object relies on its client to call its validate() method to check data integrity or on a trigger from an event such as save(). However, when using Hibernate, domain objects can be persisted transparently without the domain object being persisted beware of the fact that it's being persisted. Thus, a corrupted domain object can easily be persisted to database.

When using a rich domain model with DTO, this problem is solved:
The DTO can be used as a command object in the web layer and passed to the service tier. The UpdateService can construct two value objects fraudPaymentInfo, which contains both fraudPaymentDate and fraudPaymentAmount, and recoveryInfo, which contains both amountRecovered and dateRecovered, according to the data in the DTO and invoke the Fraud object's updatePaymentInfo() and updateRecoveryInfo(). Invariants are always maintained in the process.

2 comments:

  1. Hi Alex,

    I understand your doubts but I still prefer to use Domain Objects also in the presentation layer.
    And let me add: my domain is not anemic ;)

    For preventing from breaking domain invariants I usually do the following:

    1) As already pointed out by Debasish, I expose my setters only in the implementation class: the mvc binding framework will be able to use them, while all layers will use just the business interface *without* any unneeded setter/getter; see my old post: http://sbtourist.blogspot.com/2006/07/avoid-your-getters-and-setters-part-1.html

    2) I use specialized view interfaces that I dynamically introduce via AOP to my business objects by using the Spring XT module Introductor: https://springmodules.dev.java.net/docs/reference/0.8/html_single/#introductor

    My two euro cents,
    Regards,

    Sergio B.

    ReplyDelete
  2. Hi Sergio,
    Thanks for your comment.
    I have read your blog entry and understood your resolution, which I also adopt when I do pass domain objects to the web layer.
    However, during the binding phase, the object is constructed but not in a valid state, while entity objects as described in DDD should always have valid state after construction.
    To me, this is not a perfect solution.
    I can think of a few solutions, none of them perfect:
    1) Provide a validate() method, similar to Spring's afterPropertiesSet() method to check the data integrity. The drawback is it relies on the client's invocation of this method.
    2) Use a builder pattern: bind the input to a builder instead of the domain object. However, it would be tricky in the update scenario. Preferrably the domain object should not be aware of the existence of builders.
    3) Use mutable value objects as command objects. The domain object should always return a copy of the mutable value objects in defense of client's unintentional modification. The domain object also needs to provide an update method to accept the value objects updated in the web layer.

    My two Australian cents. :-)

    Kind Regards,
    alex

    ReplyDelete