9 Replies Latest reply on Jul 12, 2009 8:00 AM by asookazian

    Architectural Layers

    bhiles

      I’m in the process of writing an application using Seam and I keep running into examples that seem to have architectural issues with them. Yes, we can tie the UI and EJB together, but I haven’t seen examples of where there is a business/service layer under that initial tying together of the layers that can be reused outside of Seam and more of a service layer. Anyone else run into this? Am I worrying too much here? Am I missing something? Any advice?

        • 1. Re: Architectural Layers
          jeanluc

          If you need such a service layer, by all means create one. The examples that we see are not universal architectures appropriate for each project.

          • 2. Re: Architectural Layers
            asookazian

            The approach with Seam app development is that excessive layers are not required (e.g. no DTO, no DAO, no proxy, no session facade).  I've heard GKing say it himself.  Some of these have become anti-patterns with the usage of EJB3 session beans (e.g. entity classes implement java.io.Serializable interface and therefore serve as DTOs).


            With other frameworks, like Struts/EJB2.x or Spring/Hibernate, layers are recommended if not required.


            One thing to consider is a DAO layer, it's covered in JPA/Hibernate book.  I am using a DAO class for JDBC access to stored procs in my Seam/JPA app.  It's good to use a DAO layer when your app has lots of biz logic and persistence logic.  Most small CRUD apps using JPA/Hibernate don't require a DAO layer.


            Otherwise, it really depends on your project's size and complexity.  Are you integrating with other projects or consuming web services, for example?  You may want to write an abstraction layer for this.


            It would be nice if somebody wrote a Seam Recipes or Seam Best Practices book to describe these kinds of approaches, decisions, solutions, etc.  For example, when and how would you need/implement a Singleton class/component in Seam?


            When and why would you design using interfaces (like is recommended in the Spring framework?)  Your JSF directly calls business methods on a JavaBean and typically in the examples the only interface the JavaBean may implement is java.io.Serializable which is merely a marker interface so that the object can be shuttled over the wire to other JVMs.  When and why does it make sense to design to interfaces to make your code less brittle?  This is something that is rarely discussed in the Seam community AFAIK...

            • 3. Re: Architectural Layers
              jeanluc

              I'd love to hear some practical lessons from high-load sites built with Seam (if there are any). For instance, one glaring thing missing from the Seam books is that while an extended persistence context (be it container- or Seam-managed) prevents LazyInitializationExceptions, relying on it to populate what has not been loaded already results in many round trips to the database. Lazy loading is efficient only by avoiding to load something when you don't need it, but not when you do. A properly designed query that loaded everything in one shot (or a few queries only) would avoid that.






              • 4. Re: Architectural Layers
                asookazian

                that's a good point regarding the advantages (and possible disadvantages) of using lazy-loading with Seam.  The alternative is a join fetch in JPQL (or Hibernate) which promotes the fetching strategy from lazy to eager (if it's default lazy or explicitly set to lazy).  The problem here is what happens if you somehow end up loading your entire object graph (all or most entities)?  The PersistenceContext's first level persistence cache will be very large as a result and we typically do not want that for obvious reasons (e.g. memory consumption, performance).


                using a Hibernate StatelessSession interface may help in some cases when you're loading lots of entities (in the hundreds, say).  but according to the JPA/Hibernate book, this interface has its own drawbacks.


                from the Hibernate API doc:



                A command-oriented API for performing bulk operations against a database.

                A stateless session does not implement a first-level cache nor interact with any second-level cache, nor does it implement transactional write-behind or automatic dirty checking, nor do operations cascade to associated instances. Collections are ignored by a stateless session. Operations performed via a stateless session bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable to data aliasing effects, due to the lack of a first-level cache.

                For certain kinds of transactions, a stateless session may perform slightly faster than a stateful session.

                or what about when and how to use/enable 2nd level cache for read-only and read-mostly entities (e.g. Orshalick had a recent blog on this with USA 50 states in drop down as an example)?  There is some coverage on this topic in JPA/Hibernate but it is introductory and this is an advanced topic (not to mention you must decide on a cache provider like JBoss Cache, EHCache, etc.)


                There is only one reference to 2nd level cache in SiA book:



                The second-level ORM cache is shared by the persistence managers and holds persistent
                objects previously loaded through any persistence context. It is used as a way to
                reduce traffic between the application and the database. Employing an intelligent
                algorithm, it attempts to keep the cache in sync with the changes made to the database.
                However, regardless of how good this logic is, within the scope of a use case, it
                lacks the business-level insight to know exactly when data should be considered stale.
                Expecting the second-level cache to make up for the application’s inability to retain
                data is a misuse of the technology.
                The need for a stateful context acting as an intermediary between the browser and
                the database is especially important in the world of Web 2.0, where Ajax requests are
                sent to the server at a rate that far exceeds the previous usage pattern of web applications.
                Requests that leverage the conversation context save database hits and are faster
                since they’re returning data that’s held close at hand. The conversation plays another
                important role in Ajax: preventing the requests from accessing data concurrently.

                I doubt that there are more than maximum 100 high-load sites built with Seam.  How many fidelity, ticketmaster, eBay, twitter, linkedin, amazon, etc. are built using JBoss/Seam?  The performance degradation with JSF's multiple getter method calls thoughout the JSF life cycle, coupled with all the stuff Richfaces sends over the wire for a4j: and rich: component AJAX requests/responses, coupled with the heavy use of interceptors for bijection in Seam (before and after all business methods, regardless of whether the context variables need to be refreshed or not!) makes for a very slowly performing app in many cases.  Even this website which has very low load (<= 30 users!) is very slow for North American end-users at least.  For example, JSR299 and Web Beans no longer has bijection, only injection with producer methods.  And recently it has been stated by Seam core devs on this forum that excessive outjection is bad practice as it is the reverse of promoting loose-coupling (plus all in the in/out-jection is a performance hit b/c it must occur before and after each business method even if it's not required for the current use-case/code execution).


                I have seen some advanced Seam developers take some drastic measures by writing their own custom layer on top of the Seam core framework, not using injection in many cases except critical injection like for SMPC and they do not recommend a lot of the recommended components like <s:convertEntity> and some of the API if you really need a highly performant externally-facing web site.  They basically use the Conversation annotations and API and some other basic functionality from Seam core.


                There needs to be a case study published on how to optimize your Seam app (I've read the DAllen articles, those are helpful) and analyze all layers and components to see how any and all bottlenecks can be removed/improved.  Or we can wait until EE 6 servers like JBoss 6 are available and hope the tweaks are there in Seam 3.


                btw, I have tried this and highly recommend it for installing an MBean to monitor a SessionFactory (or EntityManagerFactory for JPA):


                http://docs.jboss.org/hibernate/stable/core/reference/en/html/performance.html#performance-monitoring-sf


                http://www.seamframework.org/Community/JMXMBeanForHibernateStatisticsAndSeam

                • 5. Re: Architectural Layers
                  asookazian

                  In Seam 2.1.2 ref doc, the Performance Tuning section consists of slightly over a single page:


                  36.1. Bypassing Interceptors


                  that's obviously not enough info.


                  I still don't totally understand exactly when to use the @BypassInterceptors annotation.


                  I would think that for all getter and setter calls, the interceptors should be bypassed by default, no?  Apparently this is not the case.  And when you get in a situation where the getters are being called multiple times and needless injection/outjection is occurring (which typically is not needed for getter/setter methods) then this will contribute to a needless performance hit.


                  Is there something being done to change the default behavior here or am I missing something?

                  • 6. Re: Architectural Layers
                    asookazian

                    SiA:



                    Unfortunately, if you disable interceptors, you end up stripping away all the other interceptor-
                    based functionality, not only bijection. Such features include declarative conversation
                    controls, transaction management, and event handling, to name a few. Just be
                    aware that by disabling interceptors, you may get more than you bargained for.

                    Ok, so therein lies the problem of having @BypassInterceptors default for all getter/setter methods.  Perhaps.


                    There must be something we can do to only disable some interceptor-based functionality, no?


                    Is there some refactoring being done in Seam 3 to address this?  Do we typically need injection (and in Seam's case it's not static injection, but typically dynamic injection of all context variables marked with @In) to occur for getter/setter methods???

                    • 7. Re: Architectural Layers
                      jeanluc

                      The alternative is a join fetch in JPQL (or Hibernate) which promotes the fetching strategy from lazy to eager (if it's default lazy or explicitly set to lazy). The problem here is what happens if you somehow end up loading your entire object graph (all or most entities)?

                      That's what I use. It's very unlikely you can end up loading too many entities in practice. The reasons is that most relationships are lazy-loaded so only a few need to be watch. And a decent testing effort should check what and how many queries are issued so fetches that are too eager will be spotted during development and unit testing. This is, in fact, equally applicable to the case of detecting too many queries in the case of SMPC. So either too eager or too many, it's testing that catches them :-)


                      You can also do some optimizations for read-only queries by setting setHint("org.hibernate.readOnly", true) on queries - this will prevent the creation of the snapshot (with the initial value) by Hibernate.



                      or what about when and how to use/enable 2nd level cache for read-only and read-mostly entities (e.g. Orshalick had a recent blog on this with USA 50 states in drop down as an example)? There is some coverage on this topic in JPA/Hibernate but it is introductory and this is an advanced topic (not to mention you must decide on a cache provider like JBoss Cache, EHCache, etc.)

                      There is a good discussion on it in Java Persistence with Hibernate but the crux is as you said: 2nd level cache makes sense for (mostly) read-only data, otherwise the cost of synchronizing the data across machines is similar to the cost of reading it from the database. You may use some more aggressive caching for social sites like flickr, but for financial applications you'd better relying on the database then on the 2nd level cache.



                      The performance degradation with JSF's multiple getter method calls thoughout the JSF life cycle, coupled with all the 'stuff' Richfaces sends over the wire for a4j: and rich: component AJAX requests/responses, coupled with the heavy use of interceptors for bijection in Seam (before and after all business methods, regardless of whether the context variables need to be 'refreshed' or not!) makes for a very slowly performing app in many cases.

                      Agree. I'm seeing this even now, while testing, with 300ms per RenderResponse phase to render a table with 50 rows. The database query is at least 10 times faster. Preliminary profiling shows a lot of work inside Seam and I don't see how I can remove that overhead



                      And recently it has been stated by Seam core devs on this forum that excessive outjection is bad practice

                      It's funny how revolutionary ideas ('everything you were doing is wrong, here's how to do persistence and coupling') get smoothed when met with the real world. Of course, I don't mean all what Seam has brought is incorrect (there are good points in having an extended PC, for instance), but not all the new ideas (such as 'use an extended PC and no more LazyInitializationExceptions, everything works magically now') are actually practical.



                      I have seen some advanced Seam developers take some drastic measures by writing their own custom layer on top of the Seam core framework, not using injection in many cases except critical injection like for SMPC

                      Interesting (not entirely surprising, though) and troubling - this means there is little one can do apart from meddling with the internals of Seam.


                      • 8. Re: Architectural Layers
                        bhiles

                        Dan Allen posted an article recently that seems to address some of these items re: @BypassInjectors and the time spent in Seam for data lists.

                        • 9. Re: Architectural Layers
                          asookazian

                          Brian Hiles wrote on Jul 11, 2009 05:43:


                          Dan Allen posted an article recently that seems to address some of these items re: @BypassInjectors and the time spent in Seam for data lists.


                          that is one of the best Seam articles (anywhere) I've ever read and is very important as well.  here is my followup to that article:


                          http://seamframework.org/Community/UnderstandingSeamInterceptorsAndWhenToBypassThem