• No results found

Stumbling into the Magic Servlet trap

In document Bitter Java (Page 91-95)

o View logic

3.2 Antipattern: The Magic Servlet

3.2.2 Stumbling into the Magic Servlet trap

In better designs, the servlet is only an interface point between the server-side logic and the user interface. Unfortunately, the monolithic, do-everything server script is still the design of choice for a surprising number of Internet sites. It’s not always a servlet. This antipattern can take the form of a CGI script, or an Oracle PL/SQL stored procedure, or an ActiveX request. In its worst, and arguably most frequent, form, this servlet may handle the parsing of the arguments, the back-end database connections, and the printing of the resulting HTML page. The similarities to the Magic Pushbutton antipattern that I started presenting to clients in 1990 are striking.

The program which follows is an example of a do-everything Java program taken from a real-world consulting engagement. It is based on an administra-tive program used to print all of the pages in a bulletin board. This example is actually much cleaner than the Perl program that it replaced. It has been stripped down to the basics for clarity, and the recognizable features have been changed for readability (and to protect the guilty). The servlet logic is com-pletely separated from the input HTML (which is not shown here), but the silent viper is hiding within.

package bbs;

// Imports

import COM.ibm.db2.*;

import java.sql.*;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

These lines simply import the libraries that we will need. We have imported the libraries for JDBC, Java utilities, Java servlets, and our database driver. This sample uses DB2 drivers. Generic JDBC drivers are available as well, but may have a slight performance penalty.

public class PostList

extends javax.servlet.http.HttpServlet implements Serializable {

/**********************************************************

* Process incoming requests for information *

* @param request encapsulates the request to the servlet

Antipattern: The Magic Servlet 63

* @param response encapsulates the response from the servlet */

This is the class definition. We have elected to inherit from the most com-mon servlet type, or HTTPServlet. We get a request object and a response object. These represent the initial request and the page that we will send back as a response.

public void performTask(

HttpServletRequest request, HttpServletResponse response) {

Listing 3.4 shows the meat of the workhorse method. This is the proverbial 10 KB script. The performTask method consolidates all of the different paths into the servlet to process the request. These may take the form of HTTPGETs or POSTs. In this method, we can begin to see where we start to break down architecturally. We are printing the HTML response page directly from this method. These print statements are sprinkled throughout the method, along with database requests and a little error processing.

try {

Listing 3.4 We hopelessly tangle the model and return-trip view

B

View logic

64 CHAPTER 3

B

The response writer is traditional view logic that establishes the result set and gets a writer to create the output result.

C

This print statement contains traditional view logic that prints the HTML header to the output set.

D

This database connection initialization is traditional model logic that initializes the class that establishes the connection to the database. Note that the database logic is right up against the view logic.

E

In this traditional model logic, we establish the connection initialized earlier.

F

Here we have more traditional model logic that runs the query and gets a result set.

G

Once again, we switch back to view logic that prints table headings to the output result.

H

Here, things actually get worse! We first start a result set, then print our HTML table headings, and then start to iterate through the result set.

I

This model and view logic cleans up.

To continue with the listing, we will process the methods required to process the HTTPGET:

public void doGet(

HttpServletRequest request,

H

Model and

Antipattern: The Magic Servlet 65

HttpServletResponse response)

throws javax.servlet.ServletException, IOException { performTask(request, response);

} }

This method actually gets the HTTP request, which comes in the form of an HTTPGET. The method simply passes the request through to performTask, which we use as a consolidated service method.

The sample program returns a list of all posts on all bulletin boards. For our purposes, I stop there. The unabridged program was much longer. It also had to validate the input parameters; handle constraints for the post search;

check for error conditions; manage user preferences like font, color, and view-ing style; and count and process replies. The actual Perl script that formed the basis for the JSP rewrite was over 20 pages long! Table 3.1 shows the problems with this approach; a more detailed description follows.

No separation of concerns. To efficiently maintain this system, your user interface design has to be maintained by your programmer. Ideally, we’d like the graphics designers to be working in an HTML editor and the programmer to be working in some programming environment. Since the HTML page only exists in the form of print statements in code, it’s difficult for a graphics designer to edit effectively. It has been my experi-ence that as a rule, great designers don’t program well. Programmers usually can’t design, and they generally know that they can’t design.

Unless you’re building a team of one, it is usually more cost effective to split the workload between these groups. A clean delineation between

Table 3.1 Common problems caused by the Magic Servlet. Most of these are project killers.

Problem Discussion

No separation of concerns

The user interface and model are usually maintained by different people, but the view and model are integrated too tightly.

Difficult maintenance Isolated changes in the model or view easily ripple out to force signifi-cant changes in other parts of the system.

Poor reliability Since changes cannot be isolated, one change can break other parts of the system.

Little reuse Because the application is not structured, there are no logical units for reuse beside the entire application. Instead, reuse will be limited to cut-and-paste programming.

66 CHAPTER 3 Bitter servlets

the responsibilities of programmer and graphics designer is referred to as separation of concerns.

Difficult maintenance. One result of this design is that making a change in the business process is difficult without a corresponding change in the code that returns the HTML to the client, the code that reads from the business model, the error-handling code, and the data-marshaling code. Bugs in both the presentation and the business logic must be maintained from the same place in the same way, even though the most efficient methods for each are very different.

Poor reliability. This design makes it hard to spot bugs and easy to inject them. As a rule, the brain does a much better job grasping smaller scripts and scripts with a much more limited purpose.

Little reuse. Because there are no business objects and no user interface templates, the most common reuse mechanism in this environment is cut and paste, which leads to dual maintenance and the proliferation of bugs throughout the system. In most organizations, cut-and-paste pro-gramming is responsible for more bugs than the next two problems combined. Y2K might be the best example. In this Y2K joke, the con-sultant says, “I have good news and bad news. The good news is that you only have three Y2K bugs. The bad news is that they have been pro-liferated through your enterprise 250,000 times.” Cut and paste kills.

In document Bitter Java (Page 91-95)