When I got an early glimpse of the EJB3 directions from the ServerSide conference and from the Colorado Software Symposium, I was tremendously excited. I've since tempered my enthusiasm, but it's been difficult to put those intangible reservations into words. In this article, I attempt to put some of my initial misgivings into solid, logical arguments.
You see, for me, this adventure has been a rocky one from the beginning. I got dragged, kicking and screaming, into my first encounter with EJB. Everyone was doing it, but until I joined a startup in 2000, I'd successfully avoided the beast. Soon, I was an independent consultant, and I knew that I'd have to bring down some big game to feed my family. I steeled myself to join the hunt, and a messy one it was. I mean, around me was total carnage -- broken projects, stalled careers on top of a stalled economy. I knew that I'd have to work hard to learn the ways of my game. Reluctantly but vigorously, I took on the inevitable preparations, going to monthly classes, reading five best-practices books a day, and even learning UML. At first, it proved elusive, but after months of wandering in the jungle, I finally landed the animal.
Bringing One Down
Immediately after conquering the beast within a real application, I looked upon the carcass with pride. I do admit, I expected it to be prettier. But soon, I could hear my mom standing over me, saying, If you're going to hunt one, you have to eat the whole muddy, bloated, stinking elephant. I mean, you can't just drop it and leave the carcass sitting around. What would people say?" So I ate entities, and gorged on both stateless and stateful session beans. I wrote my book and my courseware, and built best-practices white papers, and consulted. I ate it all. The thing was, I thought that after putting in all of that time, the elephant would sustain me for a while, that I'd be able to make EJB work. I expected to be able to camel those resources, and let the energy boost kick in as I needed it. And I'd occasionally have little victories, but big problems continued to plague me:
I couldn't test the stuff. I know there are testing solutions such as Cactus and J2eeUnit that made progress, but at best, those solutions made an untenable solution barely tolerable. With enterprise systems, automated testing is life.
I couldn't teach the stuff. It took too long to teach the new developers how to hunt. Each new teammate had to pass the initiation, and eat the elephant.
I couldn't escape. If I didn't eat the whole thing, the result was a stinking, rotting mess. Once I carved off that first bite, I was committed. So was my code, and my pocketbook. Also, with each new release, I felt like I had to eat a whole new elephant.
For example, take EJB security. Please. More often than not, I needed instance-based security, allowing me to secure a group of invoices based on their memberships in, say, a department or a division. But EJB wanted me to lock down individual methods or classes. This left me in the untenable position of cramming my own programmatic security on top of their mandated declarative version. Dutifully, though it gave me a little indigestion, I'd invested in the hunt, so I gagged it down.
Consider EJB container-managed persistence (CMP). While I was hoping to feel just a little satiated, my performance stank because I had to use remote interfaces and had no access to the relationships that could have let my relational database do more of the work. So I was forced to use bean-managed persistence, which is kind of like bringing your own fitness machines to the health club. And then, just when I began to feel like a survivor contestant that had been pushed too far, my jungle guide pointed to another, seemingly cleaner, tastier animal in the distance, called Elephant 2.0. Right away, I knew that I'd eat that one too.
And I stalked it for months, and like many customers, I never really completely brought it down, but I stunned it enough to start dining. And I ate: CMP, MDB, JNDI. And life was a little better, especially on the persistence front. But while I was slogging through six files to do simple persistence, my friends were laughing and dancing around their POJO applications with ordinary JDBC. And they were doing much more, with much less.
So I got newer, more powerful equipment: XDoclet, a high-powered elephant gun; Cactus, a kit that let me check each byte of elephant for disease before I put it into my mouth; and a newer IDE, which is kind of a chocolate sauce for elephant. And I was actually able to force the ever-expanding bites of elephants down, but it was getting old.
So I simply walked away from that voice in my head and the plate that was never quite empty, and immediately began to feel better. My books went from Bitter to Better (Better, Faster, Lighter Java should be in book stores and Amazon right about now.)
I want to be clear here. I respect the original elephant hunters (and inventors) for bringing enough of the industry together to settle on a standard. In fact, the original hunt was based on sound principles: we needed to introduce services outside of the scope of our business logic. In fact, some people will still only be able to eat elephant; some problems are best solved with EJB. Some can live with the inherent limitations, to achieve the benefits. To those people, I say: more power to you.
But usually, I don't have to feed a whole tribe. I just think that the hunt is targeted, sold, and used in many situations that don't call for an elephant. And when you oversell it, and force-feed too many customers a steady diet of elephant, bad things happen.
So I learned to serve other game to my paying customers. We even deployed enterprise applications on Tomcat. We slimmed down the number of physical tiers, and used POJO persistence with JDBC. Other times, we used Kodo or Hibernate. Often, we needed a few token EJB session beans for declarative or distributed transactions, but I had a feeling that other technologies provided a better answer for declarative transactions, too. I dabbled in Aspect-Oriented Programming (AOP), but didn't really feel that it was ready for me or my customers.
Finally, I discovered the simplicity of declarative transactions in solutions called lightweight containers, Spring in particular, and my evolution was complete. Call it chicken. Sure, it's bland; it takes on the flavor of the food that you prepare it with. And that's exactly the point: you can more readily adapt it to your intended purpose. Since there's room on your plate, you can choose other dishes to serve with your chicken. And chickens are a heck of a lot easier to hunt than elephants.
In truth, I expected chicken to be a tougher sell. After all, it's an open source, er, free range, project. It's also younger than the typical elephant. And "Chicken Hunter" doesn't look nearly as impressive on a resume. But I was wrong: it couldn't be easier to sell. Sure, there is a learning curve, and a new set of problems, but I like eating chicken better than an elephant. My customers like the taste, and they don't have to eat it all at once. They can bite off a little plain (POJO) persistence, dabble in inherited context for testing, and nibble around AOP for declarative transactions. I've noticed that in my body, the benefits are immediate, and powerful. I'm leaner, faster, and stronger. I could have chosen Pico, maybe with Keel, or soon, HiveMind, and I'm convinced that the benefits would have been similar.
Another Animal Emerges
So what do I see skipping around in the jungle, but a huge, elephant-sized, four-legged cheeseburger? Boy, does it look tasty. Could that be EJB 3.0 written on the bun? In fact, for EJB 3, the expert group has worked hard to pull some of the best ideas from other hunters. We'll see POJO-oriented persistence, built explicitly for the relational database model (much like Hibernate). We'll also get to use POJO façades, like we do with Spring and Pico. Now, that's a change of diet that I can live with:
I can test my objects outside of the container. InBetter, Faster, Lighter Java, I suggest that testability and simplicity go hand in hand. In fact, I believe that automated unit testing is the most significant process enhancement that we've seen in the past five years.
I can achieve full transparency, with respect to a service. In short, I can code in a POJO style. Without a doubt, the most important feature (in terms of productivity) for a persistence framework is transparency. EJB3 will bring POJO-style programming to EJB, and not just for persistence.
I have an easier strategy to deal with metadata. JSR 175 lets me include metadata, stuff that I used to have to put in unwieldy deployment descriptors, into my source code, without forcing me to put that data into my class proper.
The four-legged cheeseburger will finally sustain me, won't it? Could it even taste good? I really want to like this beast. It certainly looks the part, from a distance. So I should feel happy, right? But my stomach has been uncomfortably churning with memory, and I'm hesitant.
As I get a little closer, I have my suspicions that the huge cheeseburger in the jungle is actually an elephant with a couple of huge buns and a few condiments strapped on. Sure, the condiments will make it a little easier to choke down, but will you still have to eat the whole thing? I'm just a tourist hunter. I didn't make the elephant, so I don't have a full view. If I get the details wrong, forgive me. But from here, I see a few problems:
The Composition of the Standard
The best standards have a single purpose and vision. As with applications, effective standards build layers with progressively broader abstractions. Ideally, I'd like to see an EJB architecture that defines how to produce, package, and consume services from models formed of ordinary JavaBeans. That is the fundamental job of EJB, isn't it? Abstract away the crud that's necessary for the enterprise, so that you can better focus your code. Avoid the need to rewrite each service by defining a standard way of consuming those services. You could still build an elephant, if you're sure that you need one.
The problem is that the first cut at the EJB3 standard tries to also define the services that we will consume. Perhaps my biggest fear is that EJB3 builds yet another persistence standard, from scratch, that splinters the market and forms a barrier of entry against the next Hibernate or some current quality solutions like JDO. In fact, why tie EJB persistence to any framework? Why not allow pluggable persistence, and allow the ORM community to continue to evolve and innovate?
I see three vibrant persistence communities with successful niches. JDO (with more than 20 relational products and less than five purely non-relational products), Hibernate, and POJO code-generation strategies are all persistence approaches with solid justifications and strong followings. In fact, SolarMetric's Kodo has hundreds of relational customers, many of them with clustered high-volume deployments. And as I write this article, there's no JDO representation in the expert group. In short, I'd rather see EJB define how to package, produce, and consume services, rather than define exactly what those services should be.
In fact, this approach of defining a service within EJB is fundamentally inconsistent with the rest of EJB: for messaging, EJB lets another standard define messaging, and it embraces the standard. EJB customers would be better served if EJB3 allowed pluggable persistence, or separated another service. Similarly, EJB embraces existing standards for the expression of metadata, and the management of transactions. I know that it goes against the motivations of the J2EE application-server vendors, but it's in the best interest of customers to let them choose the packaging that makes the most sense. Let vendors bloat their packages with as many services as they want. Just don't force me to buy the whole thing to do enterprise development.
The proposed EJB3 enhancements will tightly couple EJB to J2SE 1.5. I'm all for the latest SDK, but most customers just aren't ready yet. In fact, most of the larger companies lag two years or more behind the latest JDK. Heck, a whole bunch of them are still running J2SE 1.3x. Howard Lewis-Ship still supports JDK 1.2 for Tapestry, because his customers demand it.
But EJB will require JSR 175 (.NET-style metadata), so you will definitely need SDK 1.5. This coupling will probably mean that EJB3 will not see widespread adoption for at least one and a half to two and a half years. And there's real pain now. But the real problem is that once again, I have to eat the whole elephant. Or, I have to wait two years or more. From where I sit, neither is likely to happen.
The Metadata Philosophy
I greatly appreciate the effort of revising deployment descriptors, and XDoclet sometimes does feel like a little bit of a hack. But I don't think that we know enough about JSR-175-style metadata usage models to be betting the EJB3 specification on that technology. On the .NET side, it is unclear whether this style of programming will become the norm. You can also find many knowledgeable developers in the community that think the EJB approach to metadata may be flawed. Active threads on TheServerSide and blogs on java.net point to potential problems. (See the references at the end of this article.) For example, perhaps binding metadata to source code is even moving in the wrong direction by actually coupling code that used to be independent to metadata. Also, it looks to me like the injected metadata will bind you to the container. In short, I'd much rather see best practices emerge before we standardize.
So that's where we are. When I land this four-legged cheeseburger with buns, I need to swallow a new persistence model, JDK 1.5, and a whole new, experimental metadata model, all in the name of improved productivity and simplicity. That's a huge, gaping mouthful. Explain this to me: why wouldn't I just continue to eat chicken? And why would the market opt for two to three more years of these maddening gaping mouthfuls, when in the end, they may find yet another elephant hiding beneath those buns? And if this EJB3 turns out to be better on the digestive system, wouldn't moving to chicken first make an easier transition?
Fortunately, some independent minds within the JCP, like Richard Monson-Haefel, are working hard to add real sanity to the persistence space. Some recent threads in cyberspace point to the desire to have the JDO and EJB3 expert groups work together. It looks like there's been serious movement on both sides:
Some in the EJB3 expert group, such as Richard Monson-Haefel, are willing to discuss the option of moving persistence into a separate JSR.
Some in the JDO group, such as Bruce Snyder and Patrick Linskey, are willing to move JDO as far as it needs to go to support EJB3.
If it proves inadequate, some in the JDO group have expressed willingness to build a new standard for J2EE POJO persistence.
This first step would be the most important, and the most significant. It would consolidate persistence for J2SE and J2EE under a single, complete standard for the first time. (JDO might have been that standard, but did not address object-relational mapping.) It would allow a cleaner model for integrating alternate persistence solutions. It would also unify the purpose of EJB, as a platform for producing and consuming enterprise services. And it would free customers who are struggling with CMP to move forward in a safe direction, since it looks like CMP will be supported only for backward compatibility.
As for me? I just don't want to eat a whole elephant. Please, don't make me eat the elephant again.
Better, Faster, Lighter Java: Just released, this book makes a case for simplified development, and lays out five simple principles for better, cleaner designs. It then looks at two open source projects, Spring and Hibernate, and looks at how to integrate those into better Java applications.
" Persisting Problems": This blog and post make the point that persistence should be broken out of EJB3. Some of the industry's most respected developers, including members of the JDO and EJB expert groups, agree.