1.1 Bloat Drivers
I'll illustrate the bloat by comparingitwith the famous Lewis and Clark expedition. They started with a huge,heavily loaded 55-foot keel boat. Keel boats were well designed fortraversing massive rivers like the Missouri and the Mississippi, butquickly bogged down when the expedition needed to navigate andportage the tighter, trickier rivers out West. Lewis and Clarkadapted their strategy; they moved from the keel boats to canoes, andeventually to horseback. To thrive, we all must do the same. Java hasnot always been hard, and it doesn't have to betoday. You must once again discover the lighter, nimbler vessels thatcan get you where you need to go. If the massive, unwieldy frameworkshinder you, then don't be afraid to beach them. Touse the right boat, you've got to quit driving thebloat.
Over time, most successful frameworks, languages, and librarieseventually succumb to bloat. Expansion does not happenrandomlypowerful forces compel evolution. Youdon't have to accept my premise blindly.I've got plenty of anecdotal evidence. In thischapter, I'll show you many examples of the bloat inapplications, languages, libraries, frameworks, middleware, and evenin the operating system itself.
1.1.1 Enterprise Mega-Frameworks
Java developers live with a painful reality: huge enterpriseframeworks are en vogue. That might be good news to you ifyou're among the 10% of Java developers who areworking on the hardest problems, and your applications happen to fitthose enterprise frameworks perfectly. The rest of us are stuck withexcruciating complexity for little or no benefit. Successful J2EEvendors listen to the market:
Vendors can charge mega-dollars for mega-frameworks. Selling softwaremeans presenting the illusion of value. Big companies have deeppockets, so vendors build products that they can sell to the bigboys.
It's hard to compete with other mega-frameworks ifyou don't support the same features. Face it.Software buyers respond to marketing tally sheets likePavlov's dogs responded to the dinner bell.
Collaboration can increase bloat. Whenever you get multiple agendasdriving a software vision, you get software that supports multipleagendas, often with unintended consequences. That'swhy we have two dramatically different types of EJB. The processsatisfied two dramatically different agendas.
You can almost watch each new enterprise framework succumb to thebloat, like chickens being fattened for market. In its firstincarnation, XML was slightly tedious, but it provided tremendouspower. In truth, XML in its first iteration did almost everythingthat most developers needed it to. With the additions of XML Schemaand the increased use of namespaces, XML is dramatically morecumbersome than ever before. True, Schema and namespaces make iteasier to manage and merge massive types. Unfortunately, once-simpleweb services are taking a similar path.
But none of those frameworks approach the reputation that EnterpriseJavaBeans (EJB) has ).
Figure 1-1. In theory, EJB's beans simplify enterprise programming
shows the EJB container-basedarchitecture. Beans plug into a container that provides services. Thepremise is sound: you'd like to use a set of systemservices like persistence, distribution, security, and transactionalintegrity. The EJB is a bean that snaps into the container, whichimplements the set of services that the bean will use. Within thebean, the developer is free to focus on business concerns in thebean.
My favorite childhood story was The Cat in theHat by Dr. Seuss, who should have been a programmer. Iloved the game called "Up, up, with thefish," in which the Cat tries to keep too manythings in the air at once. As an EJB programmer,it's not quite as funny, becauseyou're the one doing the juggling. Consider thisvery simple example in the first toy intothe air.
Example 1-1. Counter example: implementation
package com.betterjava.ejbcounter; import javax.ejb.*; import java.rmi.*; /** * CMP bean that counts */ [1] public abstract class Counter implements EntityBean{ private EntityContext context = null; public abstract Long getID( ); public abstract void setID(Long id); public abstract int getCount( ); public abstract void setCount(int count); public abstract Object ejbCreate(Long id, int count); throws CreateException { setId(id); setCount(count); return null; } public void ejbPostCreate(Long id, int count) throws CreateException { } public void setEntityContext(EntityContext c) { context = c; } public void unsetEntityContext( ) { context = null; } public void ejbRemove( ) throws RemoveException { } public void ejbActivate( ) { } public void ejbPassivate( ) { } public void ejbStore( ) { } public void ejbLoad( ) { } [3] public void increment( ) { int i=getCount( ); i++; setCount(i); } public void clear( ) { setCount(0); } }
The first file, called the bean, handles the implementation. Notethat this class has the only business logic that you will find in thewhole counter application. It accesses two member variables throughgetters and setters, the counter value and ID, which will both bepersistent. It's also got two other methods, called clear and increment , that reset and increment thecounter, respectively.
For such a simple class, we've got an amazing amountof clutter. You can see the invasive nature of EJB right from thestart:
[1] This class implements the EJB interface, andyou've got to use it in the context of an EJBcontainer. The code must be used inside a container. In fact, you canuse it only within an EJB container. You cannot run the code withother types of containers.
[2] You see several lifecycle methods that have nothing to dowith our business function of counting: ejbActivate , ejbPassivate , ejbStore , ejbLoad , ejbRemove , setEntityContext ,and unsetEntityContext .
[3] Unfortunately, I've had to tuck all ofthe application logic away into a corner. If a reader of thisapplication did not know EJB, he'd be hard-pressedto understand exactly what this class was designed to do.
I'm not going to talk about the limitations ofcontainer-managed persistence. If you're stilltyping along, you've got four classes to go. As theCat said, "But that is not all, no that is notall." shows the nextpiece of our EJB counter: the local interface.
Example 1-2. Local interface
package com.betterjava.ejbcounter;import javax.ejb.*;/** * Local interface to the Counter EJB. */public interface CounterLocal extends EJBLocalObject { public abstract Long getID( ); public abstract void setID(Long); public abstract int getCount( ); public abstract void setCount(int count); } This is the interface, and it is used as a template for codegeneration. Things started badly, and they'redeteriorating. You're tightly coupling the interfaceto EJBLocalObject . You are also dealing withincreasing repetition. Notice that I've had torepeat all of my implementation's accessors,verbatim, in the interface class. This example shows just oneinstance of the mind-boggling repetition that plagues EJB. Toeffectively use EJB, you simply must use a tool or framework thatshields you from the repetition, like XDoclet, which generates codefrom documentation comments in the code. If you're apure command-line programmer, that's invasive. But,"`Have no fear,'said the Cat." Let's push onward to.
Example 1-3. LocalHome interface
package com.betterjava.ejbcounter;import javax.ejb.*;import java.rmi.*;import java.util.*;/** * Home interface to the local Counter EJB. */public interface CounterLocalHome extends EJBLocalHome { public Collection findAll( ) throws FinderException; public CounterLocal findByPrimaryKey(Long id) throws FinderException; public CounterLocal create(Long id, int count) throws CreateException;}