10 Replies Latest reply on Mar 10, 2008 7:42 PM by asavitsky

    Anemic Domain Model

    barash

      This question is not directly related to Seam. But because the Seam generated source code uses this anti-pattern. I wanted to ask it here and hopefully get some feed back to illuminate my brain in this matter.
      If I understand the pattern correctly it emphasize to put domain related logic in the Domain Objects.
      So my POJOs will be more than just getter-setter and some hibernate validation logic.
      On the other hand pattern says that I should not put my business logic in the domain classes.
      When I think about it, the difference between business logic and domain logic gets completely blurry. After all, all the logic we got, even in the DB layer is related to the business!


      On the other hand I have this feeling that putting the for example validation logic inside the domain objects feels good. But considering the fact that we - as in Seam - put all our database related operations in other layer, and some of the logic needs these kind of functionality ( ie. a record validity is based on the some conditions on other records); then I will end up with having recursive dependency between my Domain Layer and my DAL.


      Any thought on this

        • 1. Re: Anemic Domain Model
          gavin.king

          I think you should stop thinking about somebody's buzzwordy patterns and anti-patterns and start thinking about where you should write code in order to end up with a truly powerful and re-usable domain model.


          What I usually do is put business logic that uses only the state of the entity and its related entities on the entity. Application logic that calls external APIs (entity managers, services, etc) does not belong on the domain model, since it is usually not part of my model of the business domain, and is by nature much less reusable than the domain model.


          But the main thing is to be practical and stop paying too much attention to lame patterns talk.

          • 2. Re: Anemic Domain Model

            Gavin King wrote on Mar 10, 2008 05:31 AM:


            Application logic that calls external APIs (entity managers, services, etc) does not belong on the domain model, since it is usually not part of my model of the business domain


            Sometimes it is - say, a business rule could dictate the removal of some child collection elements based on a change in (not deletion of!) parent element. Since removing a child element from collection doesn't trigger its deletion from the DB, there are only two options left - either to move the whole rule into the Application logic that calls external APIs part and out of the domain model, or to expose the EM to the entity beans, DDD-style. I opted for the latter approach, adding


            protected static EntityManager getEntityManager() {
                      return (EntityManager) Component.getInstance("entityManager");
                 }



            to the base entity class. It's ugly and hardcoded, but it works.

            • 3. Re: Anemic Domain Model
              keithnaas

              Or, you could use JPA cascades to cascade the delete or use the Hibernate extensions for Cascaded if you also need orphan delete :)


              Using the entityManager directly inside of the domain model seems like a dangerous use of it.

              • 4. Re: Anemic Domain Model

                Keith Naas wrote on Mar 10, 2008 04:16 PM:


                Or, you could use JPA cascades to cascade the delete or use the Hibernate extensions for Cascaded if you also need orphan delete :)


                Last time I checked, cascading delete could only work on parent object deletion. My case is a cascading delete triggered by an UPDATE of parent object.

                • 5. Re: Anemic Domain Model
                  keithnaas

                  Nope.


                  Directly from the docs - hibenate has been this way for as long as I've used it.




                  DELETE_ORPHAN applies only to @OneToMany  associations, and indicates that the delete()/remove() operation should be applied to any child object that is removed from the association. In other words, if a child is dereferenced by a persistent parent and if DELETE_ORPHAN is used, the "orphaned" child is deleted.
                  • 6. Re: Anemic Domain Model
                    franciscoperedo

                    Hi!


                    Perhaps what you need is not POJO persistence... (or at least not only POJO persistence, but something that also gives you bussines objects...


                    Something like EOF
                    is the closest thing I know that works with that style of programming might be Apache Cayenne (I wonder if it will be possible to integrate it with Seam when the version with JPA support is completed). Another possible option (but for .NET)  could be ECO.


                    On the other hand, while programming gets very object oriented and elegant sometimes it also makes it too easy to make really bad decisions performance wise... (it is also interesting to note that none of this project are AFAIK as community successful as Hibernate)


                    I see a lot of potential to avoid anemic domain models in LINQ, I think many if this anemia problems will dissapear when the LINQ support for NHibernate gets finished... and Java programmers (like us) get so envious of what can be done with LINQ+NHiberante in C# that somehow something like LINQ for NHibernate will get ported in to Java and included in the next JPA release...


                    Then we will have almost-really-true transparent persistence... In the mean time, I really enjoy working with hibernate...

                    • 7. Re: Anemic Domain Model

                      Oh, sorry, I see it now - thanks. I usually try to avoid using provider-specific extensions, but this feature might be worth deviating from JPA core.


                      Still, I'm not convinced that all domain-related logic could be coded up without referencing the EM. Say, I do have an example, where a creation of an entity M triggers creation of a number of child entities S, and there should be one S created for each record in yet another table W... well, I don't see how this could be done without a ref to EM, short of passing a list of W's to the constructor...

                      • 8. Re: Anemic Domain Model
                        keithnaas

                        Chapter 5. Entity listeners and Callback methods



                        As per avoiding provider-specific extensions, the architect in me agrees with you, but the pragmatist in me says: don't reinvent the wheel.  Some of the extensions are actually supported by other JPA implementations, they just never made it into the spec. 


                        Real world example of avoiding extensions:



                        Hibernate has a lovely set of classes for doing complex Criteria.  We can create really complex dynamic queries with minimal code.  JPA doesn't have a lot of this functionality (e.g. Restrictions) so we decided to code up a bunch of standards based stuff that in the end look much like Hibernate Restrictions.  In hindsight, it was a waste of our time.  We could have had the whole thing done in 1/10 the time and spent that extra time working on additional functionality.  In addition, how likely are we to ever deploy that application to another JPA implementation?  The only reason would be if Hibernate were to disappear, and if that were to happen, we would have much bigger fish to fry than having non standard code bases. 


                        • 9. Re: Anemic Domain Model
                          barash

                          INHO entity Listener or another service class does not make any difference here; we are still dealing with the anemic domain classes.
                          On the other hand if I want to have a reference to EM in domain objects, why not write the whole persistence methods inside the same class? Why do  need another class?

                          • 10. Re: Anemic Domain Model

                            Except that EntityListener doesn't have any more references to EM than an entity itself does, either, so we're back to square one - service locators and such...