J2EE patterns: Avoiding anemic domain models with Hibernate
The pattern itself is trivial: if you don't want other objects to access a field in a persistent object directly to preserve some invariant condition, you can put business logic to check that condition right in the persistent object and then have Hibernate either use a separate set of private accessors or configuring Hibernate to access the field directly. Hibernate effectively gets "priveliged" access to objects by manipulating classes at runtime, so it can access the raw object state during load or save operations.
- Posted by: Bill Schneider
- Posted on: January 09 2005 08:45 EST
This privilieged access is essential to preserving invariants on persistent objects. By comparison, EJB CMP forces you to make all your accessors public, leading to an anemic domain model where all the getters and setters are "dumb"; the resulting loss of encapsulation leads to
cut-and-paste business logic and a greater risk of programmer-introduced bugs.
More details are available in my blog entry.
- DAOs are an anti-pattern? by Archimedes Trajano on March 01 2005 02:26 EST
- forced public EJB CMP getters by Hans Prueller on August 08 2005 16:19 EDT
From what I can tell, it sounds like DAOs are basically anti-patterns then since they do all the transactional script stuff outside of the actual entity. Am I understanding this correctly?
That is the impresion I get. On the other hand there is still a lot of data access stuff that goes specific to hibernate that would normaly fall into a DAO. Let's say you wanted to be able to swap out Hibernate, a well architected system would let you do so without rewriting any business rules. If the business rules are in the persisted objects, the implementations of which are Hibernate specific, then you have to migrate all that business logic to the new non hibernate implementation. My understanding of correct dao use is to make the persisted object not dependant on the persistence mechanism and to put all that in the DAO (which is coded to an interface). Since hibernate does most of the work for you, the DAO implementation is almost trivial.
I guess what I'm saying is that perhaps you need to use a DAO to abstract the persistence layer away from the persisted objects, which justifies putting business logic in the persisted object's implementation.
This is not about DAOs. DAOs are just for reading/writing data and should be "dumb" with respect to business logic, rather should be there to service requests for information from a business layer.
I'm not sure from reading this piece what the flaw is in having domain objects that lack intelligence. The purpose of the domain objects is to model out entities in the world. Separating out how we act upon these entities is actually a good thing. Having read Martin Fowler's book, one of his primary criticisms of this strategy, which he labels Transaction Scripts, (aside from "It's not OO", which is not really an argument at all) is that it prevents modularity. This is not true, and the particular approach to design that I prefer nowadays is to have dumb data models which are acted upon by finely-sliced process flows. The process flow, and the steps that compose it, are described in a single class or xml file, so the entirety of what is required for a particular request is easily visible. Any step within the process can be overridden or replaced, as well as re-used in other flows. I have found this to be a very effective strategy for system design. It still allows for modularity and re-use, but resolves the primary issue of rich-domain model, which is that a single contiguous block of logic is spread out across many diverse components, and with it the flow control for its completion. This can make it very difficult in such a system to see what is happening and how a particular request is fulfilled. To me, by following the use of transaction scripts provides another, perhaps even more powerful form of "Inversion of Control".
Also, it is worth noting that with tools like hibernate the investment in an o/r mapping layer has become very small. It is also something, that no matter what ones approach, is going to end up having to be addressed by any application built today that uses a database.
I'm not sure from reading this piece what the flaw is in having domain objects that lack intelligence. The purpose of the domain objects is to model out entities in the world. Separating out <strong>how we act upon these entities</strong> is actually a good thing.
I think the piece highlighted above reflects where the disagreement came from - it's conceptual. The way Fowler (and other OO "bigots" as he put it himself, which I would admit being one) sees it is not how <strong>we</strong> act upon these entities, but rather how <strong>they</strong> act upon and among themselves. The whole idea of us replacing structs with classes has been that data needs to be encapsulated with behaviors. The anemic domain model that opens up access to all class members with passthrough getters and setters essentially drags us back to structs and defeats the purpose.
In almost all the practical projects I have worked on that employ an anemic domain model (sandwiched by stateless service and DAO layers), the maintenance situation almost always inevitably deteriorated as the project moved along and as developers rolled on and off. Why? Because with an anemic domain model, anybody can do anything from anywhere. One same piece of manipulation logic can be implemented in any service facade and any static "helper". People stopped paying attention to what would be the most sensible point to put it. And the reusability suffered also because people wouldn't bother to search through all the helpers to make sure the logic they needed was already there.
EJB CMP forces you to make all your accessors public
as far I am using EJB CMP I think I have to correct the statement above:
yes, it is right that all persistent fields are represented by public abstract getter and setter methods, but those methods being public does not mean that they are exposed outside the bean! in case of EJB if you want to make a dumb getter really become public available, it has to be declared as "interface-method" of the bean. otherwise the developer can expose a more intelligent business method instead of the dumb getter as interface-method. this way, the dumb getters and setters keep encapsulated within the EJB only.