Announcement Announcement Module
Collapse
No announcement yet.
Architectural Considerations: Spring, Hibernate and the Domain Model Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Architectural Considerations: Spring, Hibernate and the Domain Model

    Hello,

    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:

    Web Layer
    API / Service Layer / Domain Objects
    DAO Layer
    ORM objects
    Hibernate

    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?

  • #2
    Originally posted by andrew_m View Post
    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 wouldn't couple DAO layer with API service layer by using Hibernate objects. If you use Hibernate generated objects in API service layer, it will be difficult to switch to other ORM model later like iBatis. Also for any change in your database schema, likely you have to change your code all the way up to service layer. Ok, there are some pros to use Hibernate objects end to end, like memory space, or around trip persistance etc, but more cons..

    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?
    Usually we don't touch generated ORM objects. I believe the domain objects like these generted hibernate objects are for containing data. If you really want more intelligence with domain obejcts, you can consider to creat your domain objects (non hibernate generated ) for your api service layer with some levels of intelligence.


    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?
    again, contain or hide your hibernate implementations within the DAL layer. Your api or service layer will use domain objects (may constructed from hiberbate generated objects)

    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 would use DTO(or non hinbernate domain objects). It seems object bloat as you said but you get great benefit of decoupling unless your system is short team project, or memory and code size sensitive..

    Comment


    • #3
      Thanks. I agree with everything said. Just wondering what other teams do.

      I am a little scared that the team here is going to freak out about the number of classes involved in a round trip...

      Web Service / Servlet / Other "web type thing"
      DTOs for giving info to the UI
      API / Domain object & API / Service objects
      DAO for accessing the DB
      Hibernate generate ORM objects

      .... but that's the beauty of abstraction I guess. It will pay off in the long run I am sure.

      Comment


      • #4
        keep it real

        For what its worth I disagree.

        If you have choosen Hibernate then make your Hibernate real domain objects (with state and behaviour). Keep your persistance 'actions' within a service layer. For example this might be in your BusinessService:

        private DataService service;

        public void scoreGame(Long gameId) {
        Game game = service.getGame(gameId);
        game.score();
        service.saveGame(game);
        }

        Expose your domain object (detached) state to your web layer and allow the web layer to retrieve objects via their id.

        In my opinion you will end up with a much cleaner design and much less code to deal with making it easier to underdstand and therefore easier to change in the future.

        Comment


        • #5
          In service.saveGame(game) in the example above, would this be implemented by the service object interacting with hibernate directly or with the ORM objects?

          I am pretty sure we need a separate DTO layer to send to the client which is Flex. The client has specific needs and all sorts of UI controls bind directly to the objects we send it. Also the objects are serialized into a Flex/ActionScript version of the Java objects so they are pretty UI specific -- meaning that the domain objects which are intended to model the business process/problem aren't exactly what the UI would need.

          Some people are kicking around something which I would call the "grand unified domain object theory" which means the the domain objects are both the ORM objects via annotations to hiberate and DTO's. It seems clean but I just feel like it won't work in practice.

          Comment


          • #6
            In the example the DataService has a dataStore (hibernateDaoImpl) member variable and alot of the DataServices methods simply call methods on the datastore such as:

            public Long saveGame(Game game) {
            return (Long)dataStore.saveGame(game);
            }

            public List<Game> getGames() {
            return new ArrayList<Game>(dataStore.loadGames());
            }

            The DataService also retrieves data from other sources.

            It sounds like you do want to have some type of view object though. However I would still think your hibernate entities should be considered your domain objects with behaviour and then it is a case of formulating some strategy to produce and deliver your view objects (the view model can often be quite different from the domain model). The value in the system lies in the business logic of your domain model and not in the views of that model. If you are using Hibernate, to me it makes sense to use it to the benefit of the core system (i.e: use it to generate your domain model that carries state and implements behaviour).

            Comment


            • #7
              I am pretty new to hibernate so I am still not getting something...

              From what I can tell, hibernate has these low level ORM objects that are auto-generated from XML mapping files. Since these are auto generated, I don't think we can give them that much behavior, so they won't likely be "smart enough" to be a true domain model. Am I missing something?

              Are you saying you maintain domain objects and annotate them for the DB mapping?

              Comment


              • #8
                I wouldn't call myself an expert on Hibernate either but while you can autogenerate the hibernate objects (I have read!), you can also construct your domain objects and then map them so their state is persisted through hibernate. So you can treat them as normal Java objects and implement behaviour in those objects.

                In the system I am quoting from the Game has associations with Event, Pool (betting pool), Entry (with association to User) and Player. A settle() method on Game causes the game to check the Entrys for all its Pools and update the Accounts of Users who have made Entrys. In this domain model it makes sense to me to implement this as a method on Game because the game object has access to all the information it needs to complete the settlement process.

                As an add on to this design, the Game object is the parent class with child classes for different types of games. So the score() method will process differently depending on the game type.

                I am not using annotations... yet!

                Comment


                • #9
                  Autogeneration is used relatively rarely and only early in the development phase to create object skeleton, to which you then can add any desired behavior.

                  More typical approach is to create Java objects and only then mapping XML files or even avoid XML mapping completely and use annotations on your Java objects instead (note, it is possible to mix and match annotation and XML mappings if some Hibernate features are not available via annotations).



                  Originally posted by andrew_m View Post
                  I am pretty new to hibernate so I am still not getting something...

                  From what I can tell, hibernate has these low level ORM objects that are auto-generated from XML mapping files. Since these are auto generated, I don't think we can give them that much behavior, so they won't likely be "smart enough" to be a true domain model. Am I missing something?

                  Are you saying you maintain domain objects and annotate them for the DB mapping?

                  Comment


                  • #10
                    I have started a new system as well. And have started down the road of exposing my Business Model objects which are hibernate persistance objects to my service layer. The problem I see is whe you have lazy initialization. It just does not seem right to me that the service layer has an object which has an attribute called say itemList which is a set of Item objects. However, since the itemList is lazily initialized it can not access it without opening a transaction/session. It seems that your data access layer now creeps into your service layer, and your service layer now has to know that something is lazily initialized or eagerly fetched. I am at a cross roads now as to best implementation.

                    Comment


                    • #11
                      Nobody can prevent you from eager initialization, but ... You may end up fetching the whole object graph. But it may (and the most likely will) be simple too much.

                      BTW, transactions naturally belongs to service layer (or even business layer in some cases) as only those layers knows which operations shal lbe atomic from business point of view.

                      And note that inserting a DTO between DAO and service layer is not by any means better then "manual" forcing population of lazy-inited properties of your "Hibernate persistence objects". Anyway they need to be populated to transfer data from them to the DTO.

                      Regards,
                      Oleksandr

                      Comment


                      • #12
                        Believe me, I have no intention of forcing the initialization of all lazily loaded objects. What I am struggling with is whether to have a DTO/Value object transfer data between the data layer and service layer, or to just pass the hibernate domain object back to the service layer. I started out by passing the hibernate object back to the service layer, and that lead to hibernate specific or JPA specific code leaking in to the service layer. Now the service layer had to know to start a new session, refetch the object, and then access a lazily loaded attribute if it wanted to access the data. I don't believe that this type of logic should live in the service layer. It is ok for the service layer to control the over-riding transaction, but I am struggling to see how this type of persistance code belongs in the service layer.

                        Comment


                        • #13
                          Yes, it is major struggle of ORM - to make it transparent. Even not sure if it is reachable at all (in its more .

                          Concerning forcing the initialization of all lazily loaded objects - it may be lesser evil then DTO. To fill-in DTO you anyway have to obtain data from database not lazily (I mean data to be put in DTO). And if DTO contains enough data for service layer and all data to populate DTO are already in the persistence object (otherwise they would not find their way to the DTO) then why not transfer persistence object in "populated" state?

                          Ok, there is one more consideration, somewhat more pleasant - if service method handle transaction the it is in the scope of Hibernate session and so lazy initialization must succeed transparently.
                          Later addition
                          Especially, if service objects are (as it is typically) stateless.

                          Regards,
                          Oleksandr

                          Originally posted by [email protected] View Post
                          Believe me, I have no intention of forcing the initialization of all lazily loaded objects. What I am struggling with is whether to have a DTO/Value object transfer data between the data layer and service layer, or to just pass the hibernate domain object back to the service layer. I started out by passing the hibernate object back to the service layer, and that lead to hibernate specific or JPA specific code leaking in to the service layer. Now the service layer had to know to start a new session, refetch the object, and then access a lazily loaded attribute if it wanted to access the data. I don't believe that this type of logic should live in the service layer. It is ok for the service layer to control the over-riding transaction, but I am struggling to see how this type of persistance code belongs in the service layer.
                          Last edited by al0; Apr 7th, 2008, 12:22 PM. Reason: Missed sentence

                          Comment


                          • #14
                            Our approach is beginning to take shape:

                            - DTO and Web layer. DTOs are serialized and can be a subset of the full Domain objects. There will be a Web layer responsible for talking to clients and dealing with HttpServletReqeust, Cookies, etc. The Web layer will interact with the Service and Domain and assemble DTOs.

                            - Domain Layer. Rich, non-anemic fully OO Domain which models the problem and implements business logic. We are going to map the Domain to the DB with JPA annotations, or just use XML. This is still under debate. But either way, we won't have any generated orm objects and maybe no XML. So maybe these are "hibernate persisted domain objects" or something.

                            - Service Layer. Services that creates, deletes or otherwise manage Domain objects. This is business logic that doesn't belong in Domain objects.

                            - DAO Layer. These deal with the DB and create Domain objects.

                            For transactions, I think we will use @Transactional. So if we go this route our service and domain will be heavily annotated. I don't think I have an opinion on that yet.

                            Comment


                            • #15
                              Originally posted by al0 View Post
                              Yes, it is major struggle of ORM - to make it transparent. Even not sure if it is reachable at all (in its more .

                              Concerning forcing the initialization of all lazily loaded objects - it may be lesser evil then DTO. To fill-in DTO you anyway have to obtain data from database not lazily (I mean data to be put in DTO). And if DTO contains enough data for service layer and all data to populate DTO are already in the persistence object (otherwise they would not find their way to the DTO) then why not transfer persistence object in "populated" state?

                              To DTO or not is a tough call. For us, the client does have requirements that are different enough, that I think it is worth the extra work. For example, in Flex you can bind controls like checkboxes to Java object attributes. So we are going to have code in the DTOs for specific thing like ui controls, and I don't think that belongs in the Domain.

                              Comment

                              Working...
                              X