One of the most important design decisions when designing a J2EE app is whether to use EJB. EJB is often perceived to be the core of J2EE. This is a misconception; EJB is merely one of the choices J2EE offers. It's ideally suited to solving some problems, but adds little value in many apps. When requirements dictate a distributed architecture and RMI/IIOP is the natural remoting protocol, EJB gives us a standard implementation. We can code our business objects as EJBs with remote interfaces and can use the EJB container to manage their lifecycle and handle remote invocation. This is far superior to a custom solution using RMI, which requires us to manage the lifecycle of server-side objects. If requirements don't dictate a distributed architecture or if RMI/IIOP isn't the natural remoting protocol, the decision as to whether to use EJB is much tougher. EJB is the most complex technology in J2EE and is the biggest J2EE buzzword. This can lead to developers using EJBs for the wrong reasons: because EJB experience looks good on a resume; because there is a widespread belief that using EJB is a best practice; because EJB is perceived to be the only way to write scalable Java apps; or just because EJB exists. EJB is a high-end technology. It solves certain problems very well, but should not be used without good reason. In this section we'll take a dispassionate look at the implications of using EJB, and important considerations influencing the decision of whether to use EJB.
One of the key goals of the EJB specification is to simplify app code. The EJB 2.0 specification (§2.1) states that "The EJB architecture will make it easy to write apps: app developers will not have to understand low-level transaction and state management details, multi-threading, connection pooling, and other complex low-level APIs." In theory, by deferring all low-level issues to the EJB container, developers are free to devote all their effort to business logic. Unfortunately, experience shows that this is not often realized in practice. Using EJB often adds at least as much complexity to an app as it removes. Moreover, it may be dangerous for developers to "not have to understand" the enterprise software issues that their apps face. Introducing EJB technology has the following practical implications, which should be weighed carefully:
Using EJB makes apps harder to test
Distributed apps are always harder to test than apps that run in a single JVM. EJB apps - whether they use remote or local interfaces - are hard to test, as they are heavily dependent on container services.
Complex classloader issues. An enterprise app that involves EJB JAR files and web apps will involve many classloaders. The details vary between servers, but avoiding class loading problems such as inability to find classes or incompatible class versions is a nontrivial problem, and requires understanding of app server design.
Most practical frustrations with J2EE relate to EJB. This is no trivial concern; it costs time and money if EJB doesn't deliver compensating benefits.
The pernicious effects of unnecessarily using EJBs with remote interfaces include:
Interface granularity and method signatures dictated by the desire to minimize the number of remote method calls. If business objects are naturally fine-grained (as is often the case), this results in unnatural design.
These objections don't apply when we genuinely need distributed semantics. In this case, EJB isn't the cause of the problem but an excellent infrastructure for distributed apps. But if we don't need distributed semantics, using EJB has a purely harmful effect if it makes an app distributed. As we've discussed, distributed apps are much more complex than apps that run on a single server. EJB also adds some additional problems we may wish to avoid:
Using EJB may make simple things hard
Some simple things are surprisingly difficult in EJB (with remote or local interfaces). For example, it's hard to implement the Singleton design pattern and to cache read-only data. EJB is a heavyweight technology, and makes heavy work of some simple problems.
These are important considerations. Most tutorials ignore them, concentrating on theory rather than real-world experience.
Let's now review some of the arguments - good and bad - for using EJB in a J2EE app.
Here are a few unconvincing arguments for using EJB:
To ensure clean architecture by exposing business objects as EJBs
EJB promotes good design practice in that it results in a distinct layer of business objects (session EJBs). However, the same result can be achieved with ordinary Java objects. If we use EJBs with remote interfaces, we are forced to use coarse-grained access to business objects to minimize the number of remote method calls, which forces unnatural design choices in business object interfaces.
Here are a few arguments that strongly suggest EJB use:
To allow remote access to app components
This is a compelling argument if remote access over RMI/IIOP is required. However, if web services style remoting is required, there's no need to use EJB.
The following arguments for using EJB should be assessed on a case-by-case basis:
To free app developers from writing complex multi-threaded code
EJB moves the burden of synchronization from app developers to the EJB container. (EJB code is written as if it is single-threaded.) This is a boon, but whether it justifies the less desirable implications of using EJB depends on the individual app.
There's a lot of FUD (Fear, Uncertainty, and Doubt) revolving around the supposed necessity of using EJB to take care of threading issues. Writing threadsafe code isn't beyond a professional enterprise developer. We have to write threadsafe code in servlets and other web tier classes, regardless of whether we use EJB. Moreover, EJB isn't the sole way of simplifying concurrent programming. We don't need to implement our own threading solution from the ground up; we can use a standard package such as Doug Lea's util.concurrent. See http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html for an overview of this package, which provides solutions to many common concurrency problems.
Important |
EJB's simplification of multi-threaded code is a strong, but not decisive, argument for using EJB. |
Important |
The availability of declarative transaction management via CMT is the most compelling reason for using EJB. |
Important |
EJBs are a good solution to problems of distributed apps and complex transaction management. However, many apps don't encounter these problems. EJBs add unnecessary complexity in such apps. An EJB solution can be likened to a truck and a web app to a car. When we need to perform certain tasks, such as moving large objects, a truck will be far more effective than a car, but when a truck and a car can do the same job, the car will be faster, cheaper to run, more maneuverable and more fun to drive. |