Working with applications that retrieve data from databases poses interesting challenges.
For example, consider shallow vs. deep data queries. Developers commonly prefer to perform one expensive (deep) lookup, loading more than the required information in one operation over many partial (shallow) lookups of data required for display or reporting. That strategy works in some situations, but if not planned carefully, it can easily cause poor performance and high memory consumption issues.
J2EE applications involve interaction between several network resourcesdatabases being one of them. When interacting with databases, applications should be tuned to consume only the optimum network bandwidth; otherwise, the result is likely to be scalability issues. Software applications may become bottlenecked by not optimizing the network pipeline for database communications, and may also choke the network itself.
JSP and Servlet Antipatterns
Some antipatterns are specific to JSP and servlet development.
Overusing Session Data
Using the JSP session as a common data space is an easy temptation to fall prey to. The session provides a simple mechanism for storing transferring data. But an increase in site traffic and the accompanying increase in session data can cause crashes. Also, a careless dump in the session might result in conflicting keys, resulting in application errors. An even worse situation would be an error that shared data across sessions when it is not meant to be shared, potentially exposing sensitive user information.
Even without such technical issues, it is a bad idea to allow bloated sessions. Session data should be used only for information required for workflow across multiple user interfaces, and the session should be cleaned up when the information is no longer needed.
Embedded Navigational Information
This occurs when developers hardcode or embed links to other JSPs. If the page names change, someone must search for and change all the referring links in other pages. Designing a carefully thought-out navigational scheme initially can prevent this maintenance nightmare at a later stage.
Common Functionality in Every Servlet
Hard-coding functionality that is common across multiple servlets in an application makes it hard to maintain. Instead, developers should remove the repeated code from the servlets. Using a framework such as Struts provides a neat way of specifying application flow in an XML filewhich can be altered without altering the servlet code. Other common techniques exist as well, such as Front Controller and filters that you can use to remove hard-coded values at different levels.
Accessing Fine-grained EJB Interfaces
Marshaling and unmarshalling data involved in a remote call across the network can cause major time latency in applications. Latency can also occur due to multiple remote calls. Based on the needs on the application, the solution might involve redesigning the EJBs, but if that's not the case, servlets should not remotely access an EJB entity via a fine-grained API. If the EJB's expose both fine and coarse-grained APIs then servlets should use single calls to the coarse-grained API in preference to making multiple calls to the fine-grained methods.
These antipatterns involve enterprise-level concerns such as transactions and message queues.
Transactions that involve complicated processes that invoke multiple resources can lock out other threads waiting for the same resources for significant time periods. This can cause impact on performance. It's generally prudent to break such transactions into smaller chunks (depending on the application's needs), or to use alternatives such as stored procedures for lengthy database processes.
Overloading Queues in JMS
JMS provides both queue and topic destinations. A queue can house different kinds of messages, for example, map (binary) messages or text-based messages. But if you take advantage of this feature to send different kinds of messages on the same queue, it becomes the onus of the consumer to distinguish between them. A better solution would be to separate them out. You can accomplish that programmatically or by using two separate destinations, depending on the application requirements.
Web Services Antipatterns
With the rise of Web services, specific antipatterns will become apparent.
Assuming SOA = Web Service
The term Service Oriented Architecture (SOA) is often confused with Web services, but the fact is that SOA concepts were around long before Web services were born. SOA strives for loose coupling between components. It provides a software service that is consumed by another software service. Lately however, SOA has become synonymous with Web services. Just keep in mind that it's is entirely possible to base SOA on other service technologies as well.
A few other antipatterns that don't fit neatly into a category are worth mentioning.
Hard-coding JNDI Lookups
The Java Naming and Directory Interface provides a convenient way to look up object information, such as the location of an EJB interface. But JNDI lookup operations are generally expensive, especially if performed repeatedly. If you cache the results though, you can obtain significant performance improvements. One such caching scheme is to use a singleton class.
But networks aren't static. As the network changes, even the lookups can change. This means that for each network change, a programmer needs to revisit the application code, make any required changes, and recompile/redeploy the code. An alternative would be to provide configurable lookups via an XML configuration file so that developers don't have to recompile the code every time a network change occurs.
Failing to Leverage EJB Container Features
When developing enterprise components, there are two alternativesuse the services the container provides or write your own services. Although there are numerous alternatives such as Spring, EJBs are still used widely in conjunction with these frameworks. When using EJBs, you should attempt to use the container's services, such as clustering, load balancing, security, transactions management, fault tolerance, and data storage. Failing to leverage the rich features of the container where possible will eventually result in reinventing the wheel (an architecture antipattern mentioned earlier in this article).
I'm sure you've realized the significance of antipatterns in juxtaposition with design patterns. Even if you weren't already aware of the names of some of the antipatterns described in this article, you should be able to recognize their features and the problems they can cause. Classifying and naming these antipatterns provides the same benefits as classifying and naming design patterns;doing so gives software managers, architects, designers, and developers a common vocabulary and helps them recognize possible sources of error or maintenance headaches in advance.