The performance of EJB-based J2EE systems overwhelmingly depends on their design. If you get the design right, tuning the server is similar to tuning a J2SE system: profile and tune the server, targeting object creation as a priority (since the consequences in a multiuser system are an order of magnitude greater). If you get the design wrong, you are unlikely to simply tweak your way to adequate performance. In contrast, a J2SE application can often achieve adequate performance with a nonoptimal design after sufficient performance tuning. This design sensitivity is one of the reasons why J2EE design patterns have become so popular: design patterns assist everyone from novices to experienced designers in achieving adequate performance.
This design sensitivity is also the reason for the many stories about badly performing EJB projects. EJBs are a tradeoff, like most standardized APIs. In exchange for the ability to have a standard for components that developers, managers, tool vendors, and other third-party producers all work together to use, there are some overheads and design issues. Make no mistake: using EJBs compared to build-it-completely-your-way almost always incurs more overhead for your runtime system. Chapter 12 compared a proprietary communication layer to RMI (see Table 12-1), and the situation with EJBs is quite similar. Proprietary is almost always faster. It is also usually more difficult to maintain and support. EJBs have third-party support products for development, testing, tuning, deploying, scaling, persisting, clustering, and load balancing. If you don't need standardized components, EJBs may not be the best option for your project. A plain J2SE + JDBC solution has its own advantages.