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

  • Spring Roo with a services/DAO architecture

    I have been playing Spring Roo for a little while now, and when I'm not swearing at it because I can't remember the correct command (there appears to be some inconsistencies around the use of -class and -entity), I am pretty impressed.

    Anyway, the only thing holding me back from recommending we trial it at my company at the moment is the focus on domain driven design. Now I have no desire to get in to a religious debate around the pros and cons of domain driven vs services orientated; I believe they are both valid architectures, and each has its own benefits and draw backs. However where I work we have chosen to use a services orientated architecture as we believe it best suits the projects we work on.

    From a conversation I read on the Skyway blog between Ben and Jared, it sounds like Roo doesn't currently support a services orientated architecture. Now I know on one of your videos you showed using a services object within Spring Roo, however you had to write that object yourself.

    The ideal situation would be for the DAO and business logic objects to be created automatically by Roo, similar to the domain objects. I know in your presentation you said you couldn't possibly know all of the methods we may want to use, and that is correct. However you could create the basic crud methods, as well as any finders we choose to add.

    So to get to the real point of this post; If I wanted to create a Roo add-on that reused/extended the jpa add-on to create DAO and domain logic classes, where would I start? I would envision it as a choice when you installed JPA support (select either DDD or services), so you could use the same commands to create all of the fields for your entity.

    Any advice would be much appreciated.

    Thanks
    Andrew

  • #2
    Hi Andrew,

    At the moment Roo generated applications do not generate a traditional repository or service layer, but instead encourage a rich domain layer. The data access is fully included in the domain layer without actually showing up in the Java sources. It is, instead, handled by introduced code (ie Roo_Entity aspects). Since most JPA-managed repositories we see today do actually not add much value we believe Roo's approach can offer the same without the need for this extra layer. Keep in mind that Roo allows you to customize your data access as you wish.

    As for the services layer, it is really hard to figure out what you want to do in there. Roo allows you to create simple java classes to get you started. Roo cannot determine which methods for business logic that is not included in your rich domain layer you need in the services layer. Again, we don't much value in a services layer which acts as a simple facade that just hides a repository by mapping its methods 1:1. So long story short, Roo does not prevent you from creating your own services layer when needed but this cannot be generated by Roo as this layer would typically contain application specific business logic.

    HTH
    -Stefan

    Comment


    • #3
      Hi Stefan,

      I wasn't very consistent in my language. We typically use an architecture like this:
      * DAO layer - Contains the logic for writing to the data layer (typically data or web service). Named after the domain object.
      * business layer - Contains the business logic for performing operations on a domain object. Named after the domain object.
      * service layer - Handles transactions and actions that require calls to multiple business objects. These are named after the controller/s that use them, as the methods are based more around interface actions, rather than domain methods (our way of avoiding service layers that are merely pass throughs).


      My hope with service based JPA addon would be that instead of generating the JPA methods in the domain object, it would create the domain object as a POJO, and put all of the logic in a DAO object with the regular CRUD methods. I figured it could be done by copying the current JPA addon and making some adjustments, although maybe I have underestimated the complexity.

      I understand what you are saying about the extra layers not adding any value. It is true, in many causes the methods simply pass through to the DAO layer. However I tend to work with complicated applications that involve multiple databases as well as web services. For that sort of interaction I feel the extra layers help separate the complexity, although it could be that I don't fully understand how that application should be structured using DDD. As they say, it is hard to teach an old dog new tricks

      I will continue to play with Roo to see if we can use it for any upcoming projects. You never know, maybe you will convert me to a DDD way of thinking.

      Thanks
      Andrew

      Comment


      • #4
        bazza80, if you want a DAO layer, why not just replace the EntityManager in your Entities with a dedicated DAO object? This way you can have your DAO layer that fits perfectly into the Roo-generated rich domain model. Each entity will simply delegate data access operations to the DAO abstraction, which can be modified to use any available data access strategy (JPA, JDBC, IBATIS, ...).

        Cheers,
        Jukka

        Comment


        • #5
          I'd argue that JPA is the modern abstraction over persistence for enterprise Java apps, so plugging in a different DAO implementation isn't really something that is done that often. If people want to persist via some other technology, they need only provide an EntityManager implementation and have Spring dependency inject it whenever @PersistenceContext is declared on a field.

          One strong argument in support for a separate DAO layer is the ease it can be mocked during testing. However, Roo already supports mocking of the persistence layer via Rod Johnson's work in ROO-92:

          http://jira.springframework.org/browse/ROO-92

          Another argument in support of a dedicated DAO layer is the separation of concerns it provides. Certainly if a developer needs to manage most or all of the code within their project it is helpful to focus on one group of technical challenges at a time, and separate these into clear layers. However, in a Roo project the Roo system takes care of these challenges and cleanly separates the persistence code into its own compilation unit that the programmer need never deal with (unless they especially wish to). So separation of concern arguments are valid, but the fact a developer need not deal with the persistence concern themselves and the fact that Roo does use separation of concern at implementation time relieves the need of having a formal DAO layer for this reason.

          A real danger with code generation is to generate lots and lots of code (given it's so easy to do so). It would be absolutely trivial for us to generate a DAO layer, but given how trivial it would be I am really conservative about going down that path until I see some compelling and rigorous engineering arguments that show why we need a DAO layer. The problem with having a DAO layer is we have so many more types in the system (an interface and implementation at minimum, likely for every single entity), plus the more complicated IoC wiring that would necessitate (you can't just use the entity's methods anymore, but you need to now have fields in your classes that wish to use the DAOs and have these dependency injected). This level of complexity is too much like "old school Java" with its associated poor productivity. The typical arguments about swapping to alternate implementations, facilitating mock testing and separation of concern are addressed via the Roo approach without requiring a DAO layer.

          I'd also note that other modern frameworks like Rails have not found the incorporation of persistence methods into the entities (as Roo does) a problem. Indeed I'd argue the Roo approach is even more sound as it's backed by a pluggable, high performance JPA implementation and not simply the active record pattern. If having persistence methods in entities was really a major problem, a lot of Rails projects seem to be working perfectly successfully regardless.

          Comment


          • #6
            Originally posted by Ben Alex View Post
            If having persistence methods in entities was really a major problem, a lot of Rails projects seem to be working perfectly successfully regardless.
            I personally don't see any problem in having persistence methods in an Entity, simply because we're not doing much there but delegating to the EntityManager. So concerns are separated for the most part.

            In a related vein, in case one/Roo creates an abstract base entity that sports the id and version fields, would it be appropriate to put a (protected) entityManager field and the generic persist(), update() and remove methods there as well? Something along the lines of:

            Code:
            @Configurable
            @MappedSuperclass
            public abstract class PersistentObject {
                
                @Transient
                @PersistenceContext
                protected EntityManager entityManager;
                
                @Id
                @Column(name = "id")
                @GeneratedValue(strategy = GenerationType.AUTO)
                private Long id;
            
                @Version
                @Column(name = "version")
                private Integer version;
                
                public final Long getId() {
                    return this.id;
                }
            
                public final void setId(Long id) {
                    this.id = id;
                }
            
                public final Integer getVersion() {
                    return this.version;
                }
            
                public final void setVersion(Integer version) {
                    this.version = version;
                }
                
                @Transactional
                public void persist() {
                    this.entityManager.persist(this);
                }
            
                @Transactional
                public void remove() {
                    PersistentObject object;
                    if (this.entityManager.contains(this)) {
                        object = this;
                    } else {
                        object = this.entityManager.find(getClass(), this.id);
                    }
                    this.entityManager.remove(object);
                }
            
                @Transactional
                public void update() {
                    PersistentObject merged = this.entityManager.merge(this);
                    this.entityManager.flush();
                    this.id = merged.getId();
                }
                
                public static EntityManager entityManager() {
                    return new EntityManagerHolder().entityManager;
                }
                
                private static class EntityManagerHolder extends PersistentObject {     
                }
            }
            Cheers,
            Jukka

            Comment


            • #7
              Andrew,

              I am pretty sure you have read Stefan's reply, but I would like to highlight the following again -

              >At the moment Roo generated applications do not generate a traditional repository or service layer, but instead encourage a rich domain layer

              My interpretation of this is, this is the reason why persist etc methods are generated inside the domain objects and Roo does not generate any DAO.

              Hope this helps to clarify things a bit.

              Comment


              • #8
                Design scalability concerns

                I don't have much experience with Spring Roo but as Ben also said many modern frameworks (e.g Grails) are using this approach where entities can have access to some simple persistence API.

                I have been using Grails for some time now which AFAIK uses quite similar approach as Spring Roo. In general it results in more domain centric design which is good. However I still have some concerns which are mostly related to scalability of this kind of design.

                1) it is not possible to separate pure domain logic and persistence logic
                Domain entities themselves are now in charge of persisting themselves - calling some save() method.
                2) what happens if we need more complex queries?
                Now we will expose not just simple API but already some query language to our domain entity (I don't know how this is handled in Spring Roo but probably this applies for it also)
                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

                The result of above issues is that domain entities are now bigger hence harder to maintain

                Does anyone have any good solution to these issues? We could of course re-introduce Repository/DAO layer but that seems to contradict with the idea of the framework.


                ---
                rgo Ringo
                Head of R&D
                Aqris Software
                Last edited by urgo; Oct 3rd, 2009, 09:41 AM.

                Comment


                • #9
                  1) it is not possible to separate pure domain logic and persistence logic. Domain entities themselves are now in charge of persisting themselves - calling some save() method.
                  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.

                  Virtually no Roo-generated code calls any persistence method introduced into entities, with the notable exception being scaffolded controllers and automated integration tests. As such there is no need for domain objects to themselves call their own persist methods.

                  Most often someone will write a @Transactional services layer method that does something meaningful with the domain object and then calls the persist() method. Naturally if the entity was acquired in the same unit of work it will be attached to the session and therefore it isn't even required to call persist() explicitly. This automatic JPA behavior underscores the diminishing role of persistence-related methods anyway, particularly when coupled with lazily loaded associations. As such relying on special DAO/repository layer implementations to orchestrate specific update or fetch semantics is generally impractical in this era of JPA, so you're better off at looking at JPA implementation features to hook such logic in (eg event listeners in JPA).

                  2) what happens if we need more complex queries? Now we will expose not just simple API but already some query language to our domain entity (I don't know how this is handled in Spring Roo but probably this applies for it also)
                  Given Roo introduces members to Java types via AspectJ inter-type declarations, there is already separation of concern. Only the compiled class file contains both persistence methods and non-persistence methods. Roo automates the creation of finders from the zero or more finder name expressed in the @Roo annotation on the entity. As such the user doesn't need to do anything more than indicate what finder method they'd like created.

                  Certainly it is true that more complex finder queries cannot be handled by Roo and the user will still need to write those. In this regard the user will need to know JPA QL or an equivalent approach, but nothing stops the user from using ITDs in the same way as Roo does to achieve compilation unit separation. For example, the user could write a PersonFinders.aj class which introduces their very complicated finders in Person.class at compile time. That way Person.java still looks and feels like a proper entity at a source code level, but from a programming convenience level the finder is available to other layers.

                  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
                  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.

                  Comment


                  • #10
                    Ben, thank you for your thorough reply.

                    Does Spring Roo team have some general recommendation whether persistence calls should be kept out of domain objects or not?

                    Making persistence layer calls available through static methods of entities seems to advocate direct access to persistence API from domain layer. This is interesting because there has been quite heated discussion about this topic in DDD yahoo forum and some people like Eric Evans do not seem to recommend such practice in general.


                    ---
                    rgo Ringo
                    Head of R&D
                    Aqris Software

                    Comment


                    • #11
                      Hi,

                      Although I prefer using a Rich Domain model in most applications I wonder how well it suits in an enviroment like OSGi where all seems to be service-based and (I think) JPA have some interesting challenges.

                      This can be generalized to any modular environment, and modular java seems to be a very hot topic this days.

                      BTW maybe its too early to ask this?? Roos in its RC 2 version yet and it already have a bundlor add on.

                      Regards, Ral.

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          I think this thread deviated from the original question "How would one write a 3rd party addon to support service and repository layers" and became a debate about the validity of such a design. If you come from the perspective of "this is the current architectural design", then the pros/cons of it doesn't help much. Many people have chosen the service/domain/repository pattern (Spring 2.x even promoted the repository with @Repository). Also, many people have functionality that exceeds the simple entity manager and basic crud operations. I think it is valid to describe a way for people to extend the framework to support this stuff. If a framework forces someone to conform to a single methodology/design, then it won't be very useful for the masses especially legacy/enterprise applications) or is the framework designed to compete with simple web generation frameworks.

                          Comment


                          • #14
                            The EntityMetadata was designed to abstract the acquisition of persistence methods from any location, including both the entity and other types. https://jira.springsource.org/browse/ROO-287 provides the necessary plumbing so third parties can write add-ons to generate a repository/DAO layer. If someone wanted to work on a third-party add-on which provided a separate repository/DAO layer, I'd be receptive to making whatever changes are appropriate to our current base add-ons to support it (given EntityMetadata was intended to support such abstraction in the first place).

                            Comment


                            • #15
                              That would be something we would need. I am in the process of learning ROO for the purposes of potentially bringing it in-house as we have our own base repository that provides a lot more functionality then the standard EM. Also, our services are based on generated data objects, so putting persistence in that layer is not an option. Is there any documentation on writing a 3rd party addon yet?

                              Comment

                              Working...
                              X