By Mitch Stuart
Copyright © 2005 FullSpan Software
-
Usage subject to license
Document Version: $Revision: 1.5 $, $Date: 2005/11/28 02:21:26 $
However, in the past couple of years, there has been a significant and growing backlash against EJB. Among other things, we now see:
My reaction to all of this is: it's about time. In this article, I recount my personal backlash against EJBs, which started in the late 1990s. There were probably others who fought the same battle as me, but we were far outnumbered by all those jumping on the EJB buzzword bandwagon. During those days, I endured skepticism sometimes verging on ridicule when I argued against using EJBs. Now it's my turn to vent.
Note: there are several types of EJBs, including Session Beans, Entity Beans, and later, Message-Driven Beans. This article focuses entirely on Entity Beans, which are used to represent application data, typically stored in a relational database.
In part, this article discusses my experiences with particular projects in jobs that I have held. I've disguised the names of my employers by calling them Able, Baker, etc. (But since my resume is posted publicly, it would not be difficult to figure out which companies I'm talking about.)
My impressions of EJB were:
To summarize, I felt strongly that EJBs did not offer sufficent "bang for the buck", particularly for a typical enterprise application that would already be hosted in a deployment environment such as a servlet container. Certainly some features were very nice, such as declarative transaction scope. But these benefits were not worth the pain and drawbacks of the overall EJB model.
At Able, we ended up using servlets, JavaServer Pages (JSPs), and the TopLink object/relational mapping layer. At the time, TopLink was the product of a small software company, but it has been through two acquisitions and is now owned by Oracle (there is an interesting history here). This approach turned out to be very productive and stable.
One of my first tasks was to improve the performance (end-user response time) of the application. One technique that I used was to convert the front-end-to-back-end communication from fine-grained to coarse-grained. Instead of making a round-trip to the EJB for each property access, I created a "summary object" that would be populated and passed back and forth. This (and other changes including tuning the bean-managed SQL) resulted in performance gains from 70% to 200%.
Despite the performance gains, we were still suffering from EJB performance issues. First, we had heavy concurrent access to the same data, and because of EJB's restriction on multiple-thread access, we were experiencing blockage of our servlet threads that were waiting for the EJB to become available. As far as I know, this was an implicit architectural feature of EJBs, and could not be solved cleanly at the application level. We ended up introducing our own caching layer, but this just seemed ridiculous to me - isn't this what the infrastructure should provide for us?
The second continuing problem is that we could not figure out why the EJB plumbing seemed to introduce so much overhead. We were using a well-known commercial application server. Because our front-end (servlet/JSP) and back-end (EJB) were running in the same JVM, we determined that the RMI plumbing was short-circuited in this in-process case, and simple object references were being passed around (as opposed to proxies and marshalled objects). We determined this from talking from to the application vendor support staff and from our own empirical testing. This was shocking to me in two ways:
After the initial tuning and profiling efforts were complete, development split into two parallel tracks. I started to work on 2.0, and another team started to work on 1.x maintenance releases. For the 1.x team, I provided them with some prototype code to continue with the coarse granularity property access approach, which they expanded on and put into production (they called them "page objects"). Versions from 1.2 to 1.5 used EJB as the underlying persistence mechanism, with some home-grown additions such as page objects.
In retrospect, it is amazing to me that I had the guts to pursue this approach. After all, this was yanking out a major infrastructure component (EJB) that was functionally working, and replacing it with a home-grown layer. I am usually quite conservative when making major design changes. I was just so frustrated with EJBs that I was willing to do a lot of work (and take a lot of risk) to eliminate that frustration. Some of this was also due to my natural skepticism. EJBs were all the rage, they were implicitly part of every J2EE application, and yet I wasn't hearing a lot of success stories or justification for all the effort and drawbacks associated with EJBs. I felt that I had to stand up and say "the emperor has no clothes".
As I remember it, I did some prototype code, and wrote up a brief design document for the new persistence layer, and the rest of the team said, in effect, "if you feel good about it, go for it". Thanks to everyone who gave me support in those days.
The persistence layer that I designed was a thin layer around JDBC. No attempt was made to do object/relational mapping or to hide the fact that we were using SQL and a relational database. The design centered around my custom implementation of Sun's CachedRowSet. A CachedRowSet (unlike a normal JDBC ResultSet or RowSet) allows the data to be used even after the underlying database connection is closed, so it is well suited to passing around the various layers of an application. An example would be saving one or more business objects in the HTTP session of a servlet container, in between HTTP requests. Even though each HTTP request gets a new database connection from the pool, the saved objects in the session are valid regardless of the database connection state.
Baker's persistence layer turned out to be extremely successful. It was very fast and robust. After some tuning, my CachedRowSet implementation was measured as 2x faster and 30% more memory-efficient than the Beta implementation released by Sun. Later, I added object caching (with coherence across the app server cluster), which improved data access response time dramatically.
The persistence layer achieved its goals of development scalability and runtime performance and robustness. On the downside, the layer required too much knowledge of the data model by the staff. It should not be expected or required that every developer is a data modeling and SQL expert. Also, the very "thin-ness" of the layer did not lend itself to promoting the best object oriented practices in client code. It would be better to keep the lightweight nature of the persistence layer, but with less "leakage" into other layers of the application. This is the technique that I'm using in the Charlie project, discussed later.
Candidate: Do you use J2EE?We had candidates that would actually decline to continue with the interview process because we were not using EJBs. I can understand that a developer would not want to throw away whatever investment they had made in learning to develop EJBs. But the bandwagon effect was so strong, I felt that the candidates were acting without considering the actual logic of their position.
Me: Yes. We use Servlets, JSPs, JDBC. We're not using EJB though.
Candidate: Why not?
Me: [Here I would give a condensed description of the issues mentioned above.]
Candidate: Oh.
Gavin King, founder of the successful Hibernate object/relational persistence library, is a major contributor to the EJB 3.0 design. It is interesting to read his thoughts on Entity Beans in EJB3 [PDF file] and why EJB 3.0 may be the new JavaBeans.
A couple of years from now, I may have to forget everything I used to hate about EJBs and try them in a new project.