Identifying and Mitigating Risks

J2EE is a relatively new technology. Enterprise apps involve a mix of technologies such as J2EE, RDBMS, and mainframes, making interoperability a challenge. For these and other reasons it's vital to tackle risks early. When Java was less mature, I once worked on a project for a software house that developed mainframe software. My role was to lead the development of a Java web interface for a key mainframe product. As the project unfolded, I was impressed by the professionalism of the mainframe developers. They were an established team and were experts in their technologies, which they'd been working in for many years. It was clear that they assumed that "things always worked as documented". The project involved Swing applets and needed to run in both, IE and Netscape. We encountered serious rendering problems, and it took days to find workarounds for some of the more serious problems. Initially, my comments such as "this is known not to work in IE" inspired disbelief. Then I remembered my first experience as a C programmer, and the shock of working with early C++ implementations. C worked. If something didn't work, it was the programmer's fault. Yet, early C++ implementations (not compilers, but C++ to C translators) would occasionally produce semantic nonsense from correct statements. Java has come a long way since then. However, the early years of J2EE brought up many problems that seemed to be ignored by J2EE writers. For example, class loading in web apps had severe problems that required drastic workarounds in several leading products as recently as early 2001. Most tutorials and articles I've read on J2EE paint too rosy a picture of J2EE development. They fail to convey the pain and suffering that many developers go through. It's important to note that such problems don't afflict just J2EE technology. Having worked in Microsoft shops, I've encountered many irritations and "known issues" with their web technology (Microsoft products no longer have "bugs"). In the last two years, things have improved enormously for J2EE, but there's still some way to go. Discussing the bugs in particular products isn't helpful, since such a discussion might well be out of date before this tutorial is on the shelves. However, it is important to acknowledge the fact that there probably will be problems and that getting around them will soak up some development time. J2EE specifications are complex and implementations fairly new. Problems may arise from:

In the worst case, such problems may demand a design workaround. For example, the decision to use EJB 2.0 entity beans with CMP may bring to light that the chosen app server's EJB QL implementation cannot cope with the complexity of some of the queries or that EJB QL itself cannot meet the requirements efficiently. These risks can be headed off by a proof of concept early in the development project, which can prompt a decision to avoid EJB QL or choose a different app server. In less serious cases, such as a problem with a server administration tool, they might involve a server bug that slows down the development process. Successful risk management depends on early identification of risks, enabling action to be taken before resources have been heavily committed to a given approach. The following general principles are valuable in J2EE project risk management:

The following is a list of some of the significant risks encountered in J2EE projects, along with appropriate risk mitigation strategies for each. While we haven't yet discussed the concepts behind some of these problems, they should provide useful practical illustrations of risk management:


Mitigation strategies

Your development team lacks J2EE skills, threatening to result in poor choices early in the project lifecycle and making it impossible to predict project timescales.

Purchase J2EE consulting services to kick-start the project.

Hire a strong J2EE expert on a long-term basis to contribute to the project and mentor other developers.

Send key developers on training courses.

Your app is dependent on a proprietary feature of your app server.

If the feature fills a gap in the J2EE specifications, it's likely that other app servers will offer a similar feature, accessed through a different API. So isolate the proprietary functionality behind a platform-independent abstraction layer, ensuring that you only need to reimplement one or more interfaces to target a different server.

Your app server may no longer be supported, forcing migration to another server.

Use an abstraction layer, as described above, to insulate your app from proprietary features of the server.

Consider the viability of the server vendor when selecting a server, and regularly review the market.

Regularly check the compliance of your app to the J2EE specifications as described above.

Your app server may not meet your scalability or reliability requirements.

Enlist the help of the server vendor in building a simple proof of concept that can be load tested, before it is too late to switch to a different server.

Your app may not meet your performance or scalability goals.

Build a "vertical slice" of the app early in the development lifecycle to test its performance.

Your app may fail to scale as required, because while it works correctly on a single server, it exhibits incorrect behavior in a cluster.

If clustering is a possibility, consider the implication of session management and session replication in all design decisions.

Test your app in a clustered environment long before it is released in a clustered environment.

Seek assistance from your server vendor; they (and their documentation) will provide crucial information about their clustering support, which you'll need to understand to achieve good results.

A server bug makes a J2EE feature that your app requires unworkable.

Implement a vertical slice of your app as early as possible to check the implementation of crucial technologies.

Report the problem to the server vendor and hope for assistance or a patch.

Modify app design to avoid the problem technology.

Switch to a superior app server while it is still possible.

Your app requires third-party libraries (such as a particular XML library, for example) which may conflict with libraries shipped with your app server.

This risk must be addressed as early as possible through the implementation of a vertical slice. Seek guidance from the server vendor (and their documentation) in ensuring compatibility (for example, it may be possible to configure class loading to avoid the conflict).

An integrated J2EE app using EJBs and web modules encounters class loading issues that reduce productivity. When the same class is loaded by two class loaders the two copies are considered to be different classes if compared; ClassNotFoundExceptions may be encountered when one class depends on other classes that have been loaded by a classloader not visible to its classloader. This may happen, for example, when a class used in a web app but actually loaded by the EJB classloader attempts to load classes loaded by the WAR classloader, which the EJB class loader cannot see in most servers.

Understand the Java class loading hierarchy (documented in the Java.lang.ClassLoader Javadoc) and the class loading architecture of your target app server. Unfortunately, class loading strategies vary between servers, meaning that this is an area in which portability falls down.

Take care in packaging deployment units to ensure that classes are loaded by the correct classloader (WAR or EJB classloader, for example). This requires careful development of build scripts to ensure that classes are included in the correct deployment unit, rather than in all deployment units.

Consider especially carefully which classloader loads classes that load other classes by name.

Class loading is a complex area discussed in more detail in .

Code to interfaces, not concrete classes. This makes it easier to keep groups of implementation classes within the appropriate class loader.

Implement a vertical slice as early as possible to verify that class loading poses no risk.

In the event of intractable problems, consider whether the use of EJB is really necessary. Class loading issues are much simpler in web apps.

As a last resort, consider adding classes required throughout your app to the server's global classpath. This violates the J2EE specification, but can save a lot of time.

app deployment causes unnecessary downtime.

Master the deployment process on your chosen app server.

Develop a release management strategy that meets your needs.