Jeff's Blog

Musings about software development, Java, OO, agile, life, whatever.


Friday, October 14, 2005 
Database TDD Part 6: Duplication in SQL

This morning: a five-minute refactoring to further eliminate duplication in the code. SQL statements are inherently redundant. They're also risky to put together without a test against a live database.

Let's hit the code. Here's the entire User class:

import java.util.*;

public class User {
   private String name;
   private String password;
   private static final String TABLE_NAME = "userdata";
   private static String[] columns = { "name", "password" };

   public User(String name, String password) {
      this.name = name;
      this.password = password;
   }

   public String getName() {
      return name;
   }

   public String getPassword() {
      return password;
   }

   public void save() {
      new JdbcAccess().execute(String.format("insert into " + TABLE_NAME + " ("
            + User.createColumnList() + ") values ('%s', '%s')", name, password));
   }

   private static String createColumnList() {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < columns.length; i++) {
         if (i > 0)
            builder.append(',');
         builder.append(columns[i]);
      }
      return builder.toString();
   }

   public static User find(String nameKey) {
      JdbcAccess access = new JdbcAccess();
      List<String> row = access.executeQuery(String.format(
            "select " + createColumnList() + " from " + TABLE_NAME + " where name = '%s'",
            nameKey));
      return new User(row.get(0), row.get(1));
   }
}

This was three refactoring passes, each concluded with the execution of all tests in the project. The first pass involved extracting the table name to a constant; 30 seconds. The second pass involved extracting the construction of the insert column list to a separate method that uses a String array of column names; 4 minutes. The third pass involved using createColumnList from the find method; 30 seconds.

The table name and the column lists were an obvious place to start. What about the values list in the insert statement? What about the duplication inherent in the User attributes themselves?

Another thought: the Single Responsibility Principle is getting more and more abused. It's bad enough that the User domain class deals with persistence. Now there's a new method createColumnList that is a generic String utility method. It belongs elsewhere. But don't fret, we'll get to that soon.


Comments:
Speaking of the single responsibility principle, how long until you make first class objects for Column and Table, and fold some of the sql creation logic into them?

--JeffBay
 
And on another note, instead of "createColumnList", or in addition to, the more generic "join" method would be a great addition to your string utilities handbook.

Strings.join(String[] strings, String delimeter)

createColumnList(columns) {
return Strings.join(columns, ", ");
}

--JeffBay
 
Good comments, both. Not long. What I find interesting is that in 10 minutes worth of initial DB code, there's so much refactoring that can be done.

Tonight, though, I'm almost asleep already. Maybe tomorrow night.

-j-
 
Post a Comment

Links to this post:

Create a Link



<< Home

RSS Feed (XML)

Archives

February 2004   March 2004   May 2004   September 2004   October 2004   January 2005   February 2005   September 2005   October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   June 2006   August 2006   January 2007   February 2007   March 2007   April 2007   September 2007   October 2007   November 2007   December 2007   January 2008  

This page is powered by Blogger. Isn't yours?