Dotting the I s and Crossing the T s

I l @ ve RuBoard

Dotting the I's and Crossing the T's

With all the coding out of the way, the temptation is there to just dust off your hands and go find the nearest bar. But, as is often said, the devil is in the details, a lot of finishing touches should be put on an application before it's really ready to deploy.

To begin, a JavaDoc hasn't been written for anything or commented in the code. How much commenting you want to put into your code is a bit of a philosophical topic. Just about everyone agrees that this is bad commenting style:

 // Definition of addOneToNumber public int addOneToNumber (int num) // Takes one argument, number    // Add one to number and return it    return (num + 1); } 

I call this "Dick and Jane" commenting (after the "See Dick run, run Dick run" books.) I think it's fair to assume that the person reading your code has an IQ above the freezing temperature of water and can read and understand Java code.

So what do you comment, then? Anything tricky or complicated ”anything that gave you problems and made you work at it for a bit. The purpose of comments is to save time for the person reading the code after the fact.

You should also drop a line or two of comments before a major section of a method describing what it's intended to do. But, by and large, if you name your variables and methods well and avoid playing games with overly obfuscated coding, you shouldn't need more than one or two comments per method.

Listing 13.13 shows one of the methods from this chapter with comments:

Listing 13.13 An Example of Commenting
 public static Order findOrder(int orderNumber)      throws Exception {      Order order = null;      DBConnection dbConn = null;      try          {              dbConn = TurbineDB.getConnection();              if (dbConn == null) {                  cat.error("Can't get database connection");                  throw new Exception();              }              PreparedStatement pstmt =                  dbConn.prepareStatement(sql_bundle.getString("findOrder"));              pstmt.setInt(1, orderNumber);              ResultSet rs = pstmt.executeQuery();  // If no such order found, return null  if (!rs.next()) {                  rs.close();                  pstmt.close();                  return null;              }  // Create a new order to hold the one we found  order = new Order();              order.setOrderNumber(rs.getInt("ORDER_ID"));              order.setAddress(Address.findAddress(rs.getInt("ADDRESS_KEY"))); order.setCreditCard(CreditCard.findCreditCard(rs.getInt("CARD_KEY")));              order.setOrderDate(rs.getDate("ORDER_DATE"));              order.setOrderSubtotal(rs.getDouble("ORDER_SUBTOTAL"));              order.setOrderTax(rs.getDouble("ORDER_TAX"));              order.setOrderShipping(rs.getDouble("ORDER_SHIPPING"));              order.setOrderTotal(rs.getDouble("ORDER_TOTAL")); order.setCustomer(Customer.findCustomer(rs.getString("EMAIL_ADDRESS")));              rs.close();              pstmt.close();  // Now read in the items associated with the order  pstmt =                  dbConn.prepareStatement(sql_bundle.getString("getOrderItems"));              pstmt.setInt(1, orderNumber);              rs = pstmt.executeQuery();              while (rs.next()) {                  CartItem item = new CartItem();                  Product product = new Product();                  item.setProduct(product);                  item.setQuantity(rs.getInt("QUANTITY"));                  product.setISBN(rs.getString("PRODUCT_ISBN"));                  product.setTitle(rs.getString("PRODUCT_TITLE"));                  product.setPrice(rs.getDouble("UNIT_PRICE"));                  double totalPrice = rs.getDouble("TOTAL_PRICE");  // If price is zero, must be a promotion item  if (totalPrice == 0F) {                      item.setPromotionItem(true);                  }                  order.getItems().add(item);              }              rs.close();              pstmt.close();           }       catch (Exception e)              {                  cat.error("Error during createOrder", e);                  throw new CustomerActivityException();              }       finally           {              try                  {                      TurbineDB.releaseConnection(dbConn);                  }              catch (Exception e)                  {                      cat.error("Error during release connection", e);                  }          }      return order;     } 

If you count, you'll see three total comments for the entire method. Nothing else really needs to be explained; any competent Java programmer should be able to look at this method and understand it easily.

Javadoc, on the other hand, is a necessity, even if it can be difficult to write. Javadoc is your protection as a developer from having your code altered by other developers. It defines your API and allows other developers to look at the Javadoc to find the interfaces rather than mucking around in your code.

The problem with Javadoc is that it's meant to be formatted and viewed as an HTML document ”it is actually rather ugly as it lies on the page in your code. Personally, I believe in the "less is more" school for Javadoc formatting. Even though you can put any kind of HTML in your Javadoc (including pictures of your babies and links to the stuff you're selling on eBay), the more of this kind of thing you put in, the less useful the Javadoc will be when read raw. Listing 13.14 shows one of the shorter source files fully Javadoced.

NOTE

An exhaustive treatise on Javadoc can be found at http://java.sun.com/j2se/javadoc/.


Listing 13.14 Promotions.java with Javadoc
 /**  * Promotion is used to implement the Gift With Purchase promotion  * used by the Books for Geeks Web Site.  It looks for items in the  * cart which match the target condition, either by specific product  * or by category.  If the target condition is met, a gift is placed  * in the cart with the promotionItem flag set, which causes it not to  * be charged for.  *  * @author       James M. Turner  * @version      %I%,%G%  */ package com.bfg.cart; import java.util.Vector; import java.util.HashMap; import java.util.Iterator; import java.text.NumberFormat; import com.bfg.product.Product; import com.bfg.product.Category; import org.apache.turbine.services.db.TurbineDB; import org.apache.turbine.util.db.pool.DBConnection; import org.apache.turbine.util.TurbineConfig; import com.bfg.exceptions.ProductActivityException; import java.sql.*; import java.util.ResourceBundle; public class Promotion  {     private static ResourceBundle sql_bundle =      ResourceBundle.getBundle("com.bfg.cart.SQLQueries");     static org.apache.log4j.Category cat = org.apache.log4j.Category.getInstance(Promotion.class);     static Vector promotions = new Vector();     static boolean loaded = false;     protected String promoName;     protected Product targetItem;     protected Category targetCategory;     protected Product giftItem;     protected int quantityRequired;     protected boolean categoryPromotion = false;     /**      * Returns the human-readable name of the promotion      *      * @return           The name of the promotion.      */     public String getPromoName() {      return promoName;     }     /**      * Returns true if this promotion applies to a category rather      * than an individual product.      *      * @return           <code>true</code> if the promotion is applied      *                   to a category, <code>false</code> if it is      *                   applied to a single product.      */     public boolean isCategoryPromotion() {      return categoryPromotion;     }     /**      * Returns the product which must be purchased in order to receive      * the free gift. Only used by promotions which do not have      * <code>isCategoryPromotion</code> set to true.      *      * @return           The product which satisfies the requirement      *                   for this promotion.      */     public Product getTargetItem() {      return targetItem;     }     /**      * Returns the category which must be purchased in order to receive      * the free gift. Only used by promotions which have      * <code>isCategoryPromotion</code> set to true.      *      * @return           The category which satisfies the requirement      *                   for this promotion.      */     public Category getTargetCategory() {      return targetCategory;     }     /**      * Returns the product which is received if the conditions for the      * promotion are met.      *      * @return           The product which will be received      *                   as a gift for this promotion.      */     public Product getGiftItem() {      return giftItem;     }     /**      * Returns the number of the target item that must be purchased in      * order to receive the gift.  Note that for category promotions,      * this is the number in aggregate from all items that are in the category.      *      * @return           The number of target items required to      *                   receive the gift.      */     public int getQuantityRequired() {      return quantityRequired;     }     /**      * Returns the list of promotions currently available.  If the      * promotion list has previously been loaded from the database, it      * returns a cached copy, otherwise it calls      * <code>loadPromotions</code> to get the promotions from the      * database and stores them to the cache.      *      * @return           The promotions to be used on the site.      */     public static Vector getPromotions() {      if (loaded) {          return promotions;      } else {           loadPromotions();           loaded = true;           return promotions;      }     }     /**      * Connects to the database and retrieves the list of      * promotions. If a promotion is no longer valid because the      * product or category it references no longer exists, the      * promotion is ignored.      *      */     public static void loadPromotions() {      DBConnection dbConn = null;      try          {              dbConn = TurbineDB.getConnection();              if (dbConn == null) {                  cat.error("Can't get database connection");                  return;              }              PreparedStatement pstmt =                  dbConn.prepareStatement(sql_bundle.getString("loadPromotions"));              ResultSet rs = pstmt.executeQuery();              while (rs.next()) {                  Promotion promo = new Promotion();                  promo.giftItem = Product.findProduct(rs.getString("GIFT_ID"));                  promo.promoName = rs.getString("PROMO_NAME");                  promo.categoryPromotion =                    (rs.getString("PROD_OR_CAT").equals("C"));                  if (promo.categoryPromotion) {                  promo.targetCategory =  Category.findCategoryById(rs.getInt("CATEGORY_ID"));                      if (promo.targetCategory == null) continue;                  } else {                       promo.targetItem = Product.findProduct(rs.getString("PROD graphics/ccc.gif UCT_ISBN"));                       if (promo.targetItem == null) continue;                  }                  promo.quantityRequired = rs.getInt("DISCOUNT_QUANT");                  promotions.add(promo);              }              rs.close();              pstmt.close();           }       catch (Exception e)           {               cat.error("Error during loadPromotions", e);           }       finally           {              try                  {                      TurbineDB.releaseConnection(dbConn);                  }              catch (Exception e)                  {                      cat.error("Error during releaseConnection", e);                  }          }     }     /**      * Run all of the current promotions over the shopping cart.      * Before running the promotions, it removes any existing      * promotional items from the cart so that each run is a fresh one.      *      * @param cart     The shopping cart to calculate promotions for.      */     public static void runPromotions(Cart cart) {      cart.removePromotionItems();      Iterator promos = getPromotions().iterator();      while (promos.hasNext()) {          Promotion promo = (Promotion) promos.next();          promo.runPromotion(cart);      }     }     /**      * Run this promotion over the shopping cart.  If the condition is      * met, add a promotional item to the cart.      *      * @param cart     The shopping cart to calculate promotions for.      */     public void runPromotion(Cart cart) {      Iterator items = cart.getItems();      int quant = 0;      while (items.hasNext()) {          CartItem item = (CartItem) items.next();          if (isCategoryPromotion()) {              if (targetCategory.getProducts().contains(item.getProduct())) {                  quant += item.getQuantity();      }          } else {              if (item.getProduct().equals(targetItem)) {                  quant += item.getQuantity();              }          }      }      if (quant >= quantityRequired) {          cart.addPromotionItem(giftItem, 1);      }     } } 

When run through the Javadoc engine with ant javadoc , you end up with the beautifully formatted HTML shown in Figure 13.4.

Figure 13.4. Javadoc.

graphics/13fig04.jpg

As you can see, Javadoc will definitely bulk up your source code, especially if you have a lot of instance variables. I've seen source files that were 75% Javadoc when everything was done.

When to write your comments and Javadoc is another matter of debate. Personally, I do it toward the end of the project. My code goes through a lot of flux as I'm writing it, and it would be a tremendous waste to comment and document code that got ripped out a day later.

On the other hand, the end of a project is usually when things are getting nuts, with bugs coming in from the client faster than you can fix them, along with a push to move the engineering staff to the next project. It requires a degree of discipline to stick with it and put all the commenting in under this kind of pressure.

However, I find that when my brain has become truly muddled, doing some mindless documentation (and writing Javadoc is about as mindless as it gets) can be a welcome relief.

I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net