Java的简单之道不在这个方向上。充分利用Java语言本身的简单性，充分发挥OOD的威力，充分借助Open Source社群的能量，用多个框架或者类库——每一个只专注一个目的，“do only one thing and do it well”——的组合来完成任务，这才是Java走向简单的正道。
Many Java vendors and open-source projects focus on complex tools, built to solve complex problems, often under the umbrella of "enterprise" Java development. Witness the explosion of complexity in J2EE, EJB, and XML. True, there’s often a tradeoff between simplicity and power, but some key architects in the Java community are working to swing the pendulum from monolithic frameworks back toward cleaner, simpler ones. A number of new projects are helping to buck the trend toward complexity, choosing instead to build lighter, focused frameworks that can power simpler applications.
In this article, we’ll examine a few frameworks, and look at the basic principles that they use to embrace simplicity. We’ll look at a lightweight container and a persistence framework. Then, we’ll look at how the larger J2EE vendors are supporting the paradigm shift.
A few notable projects use very little of J2EE as a foundation. They are basically attempting to build a simplified notion of what it means to be a persistent object, or a container. Lightweight containers like Pico and Spring provide fewer services, but with a much less invasive architecture than EJB. Hibernate, a persistence framework, provides a persistence alternative for EJB container managed persistence (CMP).
Java Specification Request (JSR) 12 was one of the earliest requests for the Java Community Process (JCP). It was a request for transparent persistence in the form of JDO, and expressed the idea that EJB entity beans were not going to cut it. For a while, JDO faltered, but it’s seen a resurgence in the last couple of months with endorsements from the SunOne and JBoss application server development groups. With two strong JDO products in Kodo and Lido, you could say that transparent persistence has arrived.
Along the same lines, Hibernate is an open source project, founded by Gavin King, that provides transparent persistence for Java applications. I must confess that though I give an introductory Hibernate session at several conferences, I did not predict the early success of Hibernate, and guessed that it would be a bit player at best. After all, it’s proprietary; it has relatively modest development resources compared to many of the commercial OR-mapping juggernauts; and it’s an open source project, which can often work against it in larger IT departments. Still, Hibernate has burst onto the scene with tremendous early momentum, providing a surprisingly rich and fast framework.
Unlike JDO or EJB, it’s not based on byte code enhancement or code generation. It uses reflection. It has a small footprint, and runs with very low resource contention, aside from the database itself. I believe that Hibernate is successful primarily for three reasons: it’s focused, simple, and fast. Let’s look at some of the principles that have made the Hibernate project successful.
- Do one thing, and do it well. Hibernate is an object-relational mapping framework, solely for Java applications on relational databases through JDBC. That’s the lion’s share of the Java persistence community. It’s also a focused problem. By limiting the problem domain to relational databases, Hibernate is able to make some pragmatic decisions that can dramatically impact performance. For example, since the designers knew that they would be using SQL over JDBC, they could take advantage of special algorithms and extensions for high-performance outer joins. Many other persistence frameworks are not limited to relational database back ends. Hibernate effectively trades a looser coupling for higher performance.
- Strive for simplicity. The Hibernate team has invested heavily in effective documentation, and also in good examples. They also have a simple API. I was able to get my first application running in under fifteen minutes. I notice Hibernate’s simplicity in many places. Its methods are well named, and the abstraction layers are clear. I can work with pure Java beans, instead of building complex components. Ant integration and XDoclet support is already included. A framework should strive to provide the simplest support possible for its users.
- Pick your battles. If you decide to build simpler applications or frameworks, you’re going to have to decide where to focus your attention. You can’t adopt every design pattern, or make every performance enhancement. Some of my early Hibernate reservations, I’ll admit, were related to reflection. Gavin King and his team rightfully assumed that the reflection overhead would be minimal compared to the performance of the SQL queries that Hibernate would generate. Instead of optimizing reflection, the team focused on the number and efficiency of queries by delaying updates, rolling many SQL statements into one, detecting "no-ops" (like an insert immediately followed by an update and a delete), and so on. The result is a surprisingly fast framework, with the transparency afforded by reflection.
Through simplicity and better focus, the Hibernate team has settled into a nice, rapid release rhythm, and it’s served them well. The user community is growing, and they’ve just completed the second major release. But persistence isn’t the only place that the trend toward simplicity is taking root.
Lightweight containers strive to provide services for the simplest components possible. Spring and Pico are probably the most popular. If you’ve not seen them before, you may be tempted to skip this section, believing that the last thing we need is yet another container. Don’t. Lightweight containers like Spring are spreading rapidly, because they can solve problems that other containers can’t. While these frameworks are not as well known as Hibernate, at least one of them may be soon. I’m starting to hear the familiar buzz of the early stages of a successful open source project from the Spring camp. The most interesting aspects, to me, are the transparency of the objects, clean and pluggable services, and the light footprint. All of these goals lead to a simple, effective framework:
- Strive for transparency. When you’re building a solution for developers, the simplest solutions are usually the best ones. Spring is not invasive. In fact, the objects that you snap into the container are pure POJOs, plain old Java objects, or JavaBeans, to be more precise. Objects do not depend on the container. They can run outside of the container for better testability, or address other objects as POJOs.
- Allow for extension. Spring supports some simple services out of the box, like JTA and JDBC layers for transaction and database support. Spring also provides a nicely layered API that allows rapid extension by third parties. For example, you can already use both Hibernate and JDO objects within a Spring container.
- Keep a small footprint. Spring’s simplicity lets it keep a small footprint. As such, it can be used in ways that you might not expect to use your average J2EE container. It starts quickly enough to be included in tests, even if you plan to run many of them with each build. You can use Spring on the client, or within a mobile device.
Since lightweight containers work with POJOs and clearly separate concerns of various services, they are well-suited for the next generation of program paradigms like aspect oriented programming (AOP). Both Hibernate and Spring present simplified abstractions. How do we know if the abstractions will be enough?
It’s clear that cleaner, simplified abstractions are coming back, but it’s not enough to be simple. All abstractions leak. We’ll never be able to capture all of the complexity of a native database API in a simplified framework, and a lightweight container will never be able to do everything that a heavyweight container does. For this reason, it’s important to expose the abstraction layer immediately below the new one. For example, Hibernate has no notion of stored procedures. Instead, it gives you full access to the JDBC connection, so that you can call stored procedures outside of Hibernate.
Also, an adaptable, pluggable architecture, with loose coupling in appropriate areas, lets you snap out inappropriate services, and snap in ones that are more robust. For example, Spring allows pluggable persistence and transactions.
So far, we’ve mentioned a couple of open source projects. You may be interested in seeing what the major J2EE vendors are doing to support a simpler Java paradigm.
Of course, building simpler frameworks from the ground up is only one way to gain simplicity. The Java community is also trying other approaches. Some are trying whole new programming paradigms, like model driven architecture (MDA), or aspect oriented programming (AOP). Others are trying a more incremental approach, like letting tools shield us from some of the complexity.
Some vendors, especially those with a significant investment in J2EE, might view lightweight containers, Hibernate, and frameworks like them as too radical a departure from the status quo. They would rather not burn J2EE to the ground to start over. Instead, many of them would rather use a smarter set of tools to insulate developers from complexity. Sun’s Rave and BEA’s Workshop favor this approach.
Taking a page from Visual Studio’s book, BEA and Sun have built tools to shield inexperienced developers from the complexities of J2EE. The hope is that smarter tools with aggressive code generation can shield the most common J2EE developers from that level of detail.
The ability to build loosely coupled applications, especially through Web services, is a fundamental capability of BEA’s Workshop. They intend to provide a series of simplified abstractions that allow users to be much more productive. To succeed with Workshop, the challenge for BEA is twofold. They must abstract away most of the J2EE complexity for their users, and still allow enough of the underlying abstractions to peek through so that their customers can use Workshop in ways beyond the intentions of the original design team.
Which approach wins?
Will either approach step up and slay the complexity dragon? In truth, for the foreseeable future, we’re likely to see many more attempts to battle complexity. We’re simply getting to the upper bound of what most modern application development teams can handle. But we won’t be limited to any single approach. Vendors with larger investments in existing Java enterprise frameworks will tend to favor better tools that free their customers from tedious details. Other efforts, like Hibernate and Spring, will attempt to take a more radical and fundamental approach. Still others will try to make the case that Java has taken us as far as it can, so we need to move on to the next language or paradigm like C# or AOP. The playing field has been set. Let the games begin.
- Check out Hibernate, and related documentation here: http://www.hibernate.org/
- Read Introduction to Hibernate: http://www.theserverside.com/resources/article.jsp?l=Hibernate
- Download chapters from Manning's Hibernate In Action: http://www.theserverside.com/resources/HibernateReview.jsp
- Get the Spring framework here: http://www.springframework.org/
- Read Introducing the Spring Framework: http://www.theserverside.com/resources/article.jsp?l=SpringFramework
- Hear an interview with Gavin King here: http://www.theserverside.com/events/library.jsp#king
About the Author
Bruce Tate is a consultant in Austin, Texas. His books include best-selling Bitter Java, and Bitter EJB. He is a regular speaker at industry conferences, including TheServerSide Symposium, and the No Fluff, Just Stuff Java Symposium series. He has 15 years of development experience, and is the founder and president of J2Life, which offers consulting and services in the areas of Java persistence, developer marketing, and the application development process.