Announcement Announcement Module
Collapse
No announcement yet.
Spring Roo with a services/DAO architecture Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    https://jira.springsource.org/browse/ROO-301 represents the feature request for separate DAO/repository support. Please vote for the issue if you'd like it.

    Comment


    • #17
      So what is the pattern people are using with DDD for business logic?

      I've got a pretty nice domain model going in roo and, having written many "old school" style DAOs, I'm totally sold on the Aspect-driven approach, it satisfies all my requirements beautifully. But I am new to the whole DDD approach. I've seen plenty of rails code with 2000+ lines of code in a Model class that is just a wasteland of pure code entropy waiting to happen. To avoid this, similar to what seems to be encouraged in grails, I'm planning on creating a com.mycompany.service package that contains things like BigBusinessLogicConcernService. Theses "services" will be responsible for performing complex business logic that involves 2 or more entities. These services can then be injected into controllers (just like grails again) so that concerns remain correct in the different layers.

      This is the approach that seems correct to me but I'm interested in hearing others feedback on this concept - given that I'm already 100% down with the DDD Kool-aid and have no interest in traditional "DAO" like objects etc.

      Thanks
      Steve

      Comment


      • #18
        I totally agree that once you start getting a lot of business logic you should factor it out into separate classes to improve testability, maintenance and understanding. I tend to use a services layer where multiple objects are involved that do not already hold references to each other.

        Comment


        • #19
          How does this rich domain model get serialised during an RPC/JMS call ? I noticed that the EntityManager is transient so it does not get serialised. Also when the service receives that entity and deserialise it, there will be a need to inject an EntityManager to activate persistence. Is this something that the container will cater for automatically within JEE or is this something that needs to be done manually ?

          Comment


          • #20
            Roo uses Spring Aspects, which defines an @Configurable annotation. Roo projects use Spring Aspects as an "aspect library", meaning AspectJ performs compile-time weaving of advice defined in the library. @Configurable has a pointcut which causes dependency injection on both construction as well as (de-)serialization of an object. Therefore the EntityManager will be reinjected when deserializing.

            Comment


            • #21
              Originally posted by Ben Alex View Post
              Because JPA is so heavily used in current enterprise Java apps, and it provides a persistence layer abstraction via the EntityManager interface, it is possible to provide an alternate implementation if required.
              I've been using ROO for a while, the persistence layer generally works fine for me. However, my colleagues and I did found it makes testing of controllers and business service objects harder to test (harder to mock compare to a DAO pattern) due to the direct access to static domain methods. I'd wish a DAO pattern can be available besides default pattern in the ROO persistence layer.

              Comment


              • #22
                Non-controller front-end technology

                I have enjoyed reading Ben's arguments for DDD on this thread and a few others around the web. I've been using Grails for a while and I totally agree that ousting the DAO layer is just a great feeling. I haven't read a lot about DDD before and was surprised that according to Ben's arguments (and lack of a Roo create service command) DDD involves removing the services layer as well. Grails was quoted as an example however it should be noted that Grails DOES have a service layer and the documentation encourages you to use it.

                While I get my head around this new idea, my question regards the use of front-end technologies like Flex where you traditionally tend to call directly to the services layer rather than to a web controller. If I use Flex and DDD with Roo, where do you recommend that I direct my Flex calls? Should they then go directly to the domain objects? Or should I create a service layer just for Flex's sake? Or a kind of controller layer?

                Perhaps the Flex plugin will give us some answers when it comes.

                Thanks,
                John

                Comment


                • #23
                  DAO Layer

                  Originally posted by Ben Alex View Post
                  90% of the time I would expect the persistence methods to be called from other layers, like tests, services or controllers. Sometimes an entity might have a good reason to lookup some information, but it's the exception rather than the rule because chances are the entity holds an association to another entity via normal Java references and therefore can depend on transparent persistence (eg lazy initialization).

                  I'm actually a big fan of using JPA features to ensure entities aren't particularly aware of making explicit persistence method invocations. To achieve that you need to use the various JPA features that exist. I believe the function of repositories is diminishing as we end up with smarter APIs like JPA that use clever language features (dynamic proxies, AOP, load-time weaving, instrumentation, inter-type declarations etc) to address the individual issues that historically motivated a repository or DAO layer. Dedicated repository/DAO layers probably still make sense if you're trying to do JDBC alone and don't have the benefits of an intelligent persistence layer like JPA that sorts out many of the technical issues that repository/DAO layers focus on.
                  The idea of having the persistence methods within entity's is not reflected in other spring samples projects. Is there any reason why you wouldn't adopt this idea there? as it seems to be valuable direction going forward.

                  Comment


                  • #24
                    Service Layer Usage

                    I see the service layer as a necessary component in application design. The service layer would provide business functions that would be invoked potentialy from any/all of the following:
                    • Controller methods
                    • SOAP web services
                    • Spring Batch processes
                    • Spring Remoting (RMI, HTTPInvoker, etc)

                    You can vote up this feature at ROO-340

                    What would be a good approach to configuring this in the current implementation of ROO 1.1 without pushing in the controller methods?

                    Thanks,
                    Gordon

                    Comment


                    • #25
                      Originally posted by urgo View Post
                      3) what happens if we need to encrypt some data before saving to database?
                      one solution is to use separate transient and persistent fields but even then entity would most likely need to depend on some encryption API

                      Ürgo Ringo
                      Head of R&D
                      Aqris Software
                      Originally posted by Ben Alex View Post
                      You have a number of choices here. You could look at JPA event listeners as touched on above, or alternately you could employ some clever AspectJ field get/set advice. The advice could perform actual encryption/decryption. Alternately you could tackle encryption/decryption in the layers closer to the user, as that way your business logic in the services layer need not content with potentially-encrypted values. Of course some databases provide encryption themselves, and then you have encrypted file systems as well. These latter layers are likely to provide better encryption performance and not adversely impact your ability to perform SQL queries (as the queries can be expressed in an unencrypted form). It really depends on the business goals of encryption/decryption in the first place, but I am confident the requirement can be satisfied despite having persistence members introduced to the entity.
                      Just a quick observation on this question, (albeit a number of months late...!), I would suggest the tidiest way to persist a field as encrypted to the database would be to create a Custom Type Definition using your JPA provider, (ie in HIbernate using the @TYpeDef annotation).

                      Comment


                      • #26
                        Ok.. I fast forwarded through the topic, and after sensing what the passions are like around here.. let me express my humble opinion (I might be wrong on certain points but anyway this is subject to critical evaluation):

                        In terms of the "way" Roo handles persistence, it just clones Grails (not that I am familiar with it anyway), and implements the "ActiveRecord pattern".

                        In general most experienced programmers do not think of "patterns", at least not in the way those are expressed in the mainstream Java books (from 4 years ago).

                        A "pattern" should be abstracted into a separate class/type.

                        The way Roo handles persistence results in an explicit code duplication. Unnecessary references to an EntityManager are kept via lots of domain objects, which leads in additional memory consumption, which can be avoided by using pure clean OOP design.

                        Here my point is, the way Roo handles persistence is in conflict of OOP. Its just plain copy and paste "on steroids".


                        Let me state how do I handle persistence in my "real" projects:

                        I had not been favoring DAOs since my adoption of the Spring framework. Daos are in conflict with JPA. a.k.a. an exclusive or. either JPA or a DAO, since they are basically the same.

                        What I favor is a "de facto" service layer. I am saying de facto, because I am not using any annotations on it or whatever. I have created a class named "CoreManager" which handles all operations, which in turn are invoked by the web interface and any other interface we could be about to implement. Adding core logic in the web interface results in a lock-in. Lock-in is not something Roo is saying to support/endorse. Lock-in should be wiped out.

                        Essentially the web interface is just that - an interface, the controller should invoke the service layer. For comparison, thats the real purpose of the respective core SpringFramework extension points. Thats why it is extensive, cos we do not know what extensions to the core are to be introduced by Spring users.
                        Proper OOP just saves you nerves and whathaveyou. Why should you be refactoring your web controllers at a later point, where had you just implemented a service layer, no problems would arise.

                        Here is what attracted me at first towards Roo. I am facing a problem in my service layers which essentially is duplicating query logic (in the NamedQuery annotation), and I am searching a way to refactor those by (a.k.a. I say what fields we are involving in the query "stereotype", and my solution just handles the low level details).

                        Essentially I am looking to code high level stuff, and the framework to solve the low level stuff.

                        Roo can solve all my problems, and respectively the community's.
                        BUT... no lame code duplication.
                        Code:
                        privileged aspect EntityClass_Roo_Entity {
                            
                            @PersistenceContext
                            transient EntityManager EntityClass.entityManager;
                        What is this ? Is this saving complexity ? Is it not introducing package circularities ?

                        I have recently witnessed a presentation by Juergen Hoeller himself talking about the importance of not introducing any package circularities.
                        I.e. package 1 knows about package 2, but not the other way around.
                        He stated and later proved that the spring framework contains none of those.

                        Here this, my apologies, lame ActiveRecord pattern introduces cross-cutting concerns, or a kind of (I am not considering myself a real expert in the field of AOP). Also it breaks encapsulation and data abstraction.

                        By the way: Inter type declarations do not remove those. It is essentially a class declaration, but not declared in that physical file. It is just POCD (plain old code duplication [in the dress of a flawed AOP-based implementation]).
                        Those .aj files just contain duplicate code. Its ugly. And by the way, just because AOP is involved, it doesn't mean by itself that bad design is impossible. It does not save you from that.

                        The proper thing to do should be NOT:

                        Code:
                        entityInstance.persist();
                        rather:

                        Code:
                        serviceManager.persist(entityInstance);

                        The same principle applies to "finders". Those should not be members of an entity class, rather of the service layer class.




                        Please.. deal with it. For the sake of us all...



                        Any questions are accepted.
                        Last edited by sandstorm; Jul 5th, 2010, 08:34 AM.

                        Comment


                        • #27
                          Sandstorm,

                          You are addressing 2 layers of the application here, services and DAO/Persistence (I will refer to persistence layer below).

                          1. The service layer should be for business functions, not entity.persist() as you had mentioned. Service layer functionality is not always a simple entity specific process but an aggregation of several entity data requests to perform the business functionality. With this concept in mind, you would need to go from the Service layer to a persistence layer.

                          2. The persistence layer does (as Ben mentioned in a previous post) support separation of concerns through aspects. So, Roo is proper OO design and proper in supporting separation of concerns. Keep in mind that with JPA almost all of your persistence layer code would be 1 or two lines code. In fact, that code would be almost exactly the same from one entity to another. Therefore, it is a perfect fit for an aspect, otherwise you would be repeating code yourself (copying one persistence entity to another and renaming the entity name to another - copy/paste, find/replace entity1 with entity2, save... rinse and repeat).

                          Also, In reference to EntityManager... Roo allows you to change the persistence type with a single command at any time without impacting the business functionality.

                          See: EntityManager

                          In reference to ActiveRecord... I would have to dust off those brain cells back a few years ago when Ruby was touted as the "Java Killer".

                          In reference to circular code... I don't see it. Nor do I see any code that crosses layer boundaries inappropriately. View <--> Controller <--> Entity Persistence.

                          Roo is intended to be a Rapid application development tool. You can certainly create add-ons for specific needs. Also, when you use Roo, you can "Push-In Refactor" code into your classes and Roo then ignores those methods. At that time, you have the opportunity to customize the code as your needs demand.

                          Regards,
                          Gordon Dickens

                          Comment


                          • #28
                            Well..

                            Let me express my feelings again, in a shorter and neater way.



                            DAOs are to be dismissed, because they solve a problem of data accessing. For example returnin objects from JDBC. When a platform like Roo is JPA based, the DAOs are a redundancy.

                            The service layer should contain a method havind this signature:

                            Code:
                            public void persist(Object o)
                            rather than:

                            Code:
                            public void persistBook(Book b);
                            public void persistAuthor(Author a);
                            My way (the former) introduces no code duplication.

                            Look at what the aspects contain. Every entity contains:

                            Code:
                            @Transactional
                                public void EntityClass.persist() {
                                    if (this.entityManager == null) this.entityManager = entityManager();
                                    this.entityManager.persist(this);
                                }
                            Is this a cool thing ?
                            The fact that a tool generates code for you, and that code is placed in files implementing something called "aspects", is not "separation of concerns" necessarily.

                            All aspects generated by Roo contain duplicate code among themselves. Thats bad.

                            Look at the body of the above method. Thats wrong. The right thing is:


                            Code:
                            public class ServiceManager {
                                    @PersistenceContext
                                    EntityManager em;
                            
                                    @Transactional
                                    public void persist(Object o){
                            	    em.persist(o);
                                    }
                            
                            
                                     // other, more complex, service methods
                            }
                            Entity creation is a business concern. The fact that it shares JPA signature, which in turn is typically considered to be a data access concern, doesnt mean anything.



                            A record is not something that should know of entity managers etc..
                            Consider a standalone app that doesnt access entityManagers and uses the entity classes (they are POJO, remember?). Why should those object know about JPA at all ?

                            In reference to circular code... I don't see it. Nor do I see any code that crosses layer boundaries inappropriately.
                            Entity instances are not a part of the service layer. Thats all. From this perspective you could see it.

                            Package circularities are present..

                            All matter discussed here is like the emperor's new clothes.
                            Dont get me wrong. Roo's core idea s fine. Its amazing to have something to fulfill one's laziness... BUT.. not in a boilerplate way.


                            Btw I am not really informed how to make addons.. that would be nice but.. anyway. Things need change. Thats why versions are so common, we dont even notice what they mean. Every piece of software is presumed to be at least "not-perfect". And thats normal.

                            The point is that Roo and its message is so good, that it deserves to get better. Which comes at the price of overcoming ego and doing the right thing.



                            An analogy is reproduction in the animal kingdom.

                            You can reproduce by division where the child inherits all the parent flaws. (like forking, when you fork something, or copy a concept, you start off with all the parents bugs and flaws, just like the active record example I gave.)

                            You reproduce by sex, where the child inherits all good parts of its parents, and, more importantly, is being born without any parasites.



                            After all my post got pretty big, huh
                            Last edited by sandstorm; Jul 6th, 2010, 04:46 AM.

                            Comment


                            • #29
                              I agree with you to a point on the Services layer. Roo does not currently provide any hooks for this, it is a manual endeavor. So you start with Roo, and once tests are in place we refactor the code to suit our application needs.

                              For Services:
                              Each Entity type typically has its own Service class addressing business functions at a higher level of abstraction not simply a call to persist(), although if that is all that is required it should go there, in this simple example I would agree with you, but it is usually more coarse grained like account.calculateYearEndResults(). Which would potentially interact with many different service DAOs.

                              As for transactions, they should be promoted to the service layer in this case. However, transactions at the entity layer will, by default, participate in a transaction declared in a service.


                              Does this make sense, or do I need more coffee?

                              Gordon

                              Comment


                              • #30
                                Final decision on Services Support/architecture?

                                As I followed this thread I was not clear what direction is ROO going to take to support the example scenarios presented above for services.

                                I am considering using Roo, but the services paradigm is crucial for me. Last entry was from six months ago, so I'm curious if it was settled.

                                Comment

                                Working...
                                X