I am working on the overall design of a brand new system, so no legacy issues are relevant, and we have decided on Spring and Hibernate. I have found lots of useful information here and elsewhere, but what I am missing is the notion of what the best practices are for this type of system in 2008, based on everyone’s experience.
So looking top down I am guessing we would have something like this:
API / Service Layer / Domain Objects
Here is my take at what these layers do, along with some questions...
Web Layer - Does web stuff. Duh.
API / Service Layer - Implements business logic. This is what is exposed to all external consumers of the system (there will be others besides the web layer).
Domain layer - Models the business problem. These interfaces, along with the API layer will also be exposed to the outside word (web, etc), but nothing else will be.
DAO Layer and ORM objects - Interacts with the DB via hibernate.
?? OK so here is where things get fuzzy. The API layer will use the DAO layer to get info from the DB (Spring can inject DAO impls), but what should the DAO layer return to the API layer…. full domain objects (which I consider part of the API), or the ORM objects that Hibernate generates with its DB mapping?
I think the way the ORM objects are created has a big effect on all this. If we assume that we manage hibernate mappings in an XML file (one per table/ORM object), then hibernate will GENERATE the ORM objects for us. This is fine, but then we are not going to add any intelligence to these ORM objects, they are going to be simple getter/setter bean things just for talking to hibernate. So are we going to have all this code creating meaningful Domain objects (which may be a bit less anemic) out of the ORM objects?
?? If we were able to auto-generate the hibernate XML (and SQL) from annotated ORM objects, then since we are building the ORM objects, maybe we can put some more intelligence into them? But then can the annotated ORM objects become something more, like a Domain object (or an implementation of one)? Or do we just annotate the Domain objects and not have an ORM layer at all?
I guess it all comes down to this…. how to the hibernate ORM objects fit into this architecture? Are they totally hidden from the API via the DAO? Can we forgo these objects an use annotations on our Domain objects?
The OO purest in me feels that everything should be totally separate. The Domain / API is the model of our problem. That should be developed independently from Hibernate or Spring. This is what we used to do 10 years ago right? My only problem with all this is it seems like object/class bloat. We could have DTOs converting ORM objects backed by XML into Domain/API objects. Then Service/API objects performing business logic on them. Then Web layer code converting Domain/API objects into View/Value type data objects for the GUI (json for example). Add in the fact that you have interfaces and impl classes everywhere at it seems like you need ten million classes for a simple round trip from the UI to the DB (Web VO / Domain / Service-API / DTO / ORM object). And if these things are somewhat similar we have all this code setting and getting stuff from one layer to another. Can’t there be just one thing we pass around?
Is there some way to make the Domain/API objects both smart enough for business logic, but dumb enough (or maybe smart enough depending on your point of view) to be used by the Hibernate APIs / DTOs for persistence?
And if we are only using Hibernate, and will be for the foreseeable future, do I really need the DTO layer? Can my API just talk to hibernate via the ORM classes? I mean common… I am stating to see why people like ruby these days
This whole discussion also bleeds to the anemic domain model anti-pattern battle as well. I think I want a somewhat smart Domain model that uses inheritance and all that OO stuff. But if these domain model objects also double as hibernate mapper things maybe that breaks down?