Agile Renaissance


On the Primacy of Intention in Programming

Print the article

This entry was posted on 3/18/2007 7:49 PM and is filed under Development.

On a discussion list I recently observed one of the members express frustration with the way he was developing code. He wanted to add a field to a class. So he wrote the following test:

    @Test
    public void testSField() {
        SObject sObj = new SObject();
        assertEquals(null, sObj.getSField());
        sObj.setSField("zork");
        assertEquals("zork", sObj.getSField());
     }

When he tries to run this, he gets compilation errors and so he uses the auto-correction feature of Eclipse which produces this:

    public class SObject {
        public Object getSField() {
            return null;
        }
        public void setSField(String string) {
        }
    }

He then says than he does as little as possible to make it pass the test and so his code ends up like this:

    public class SObject {
        private String sField;
        public Object getSField() {
            return sField;
        }
        public void setSField(String string) {
            sField = string;
        }
    }

At which point, he expresses his joy, but then complains that the method getSField is returning an Object and not a String and that he has to go and correct. He occasionally forgets and then his library users discover the problem and complain. He then asks how do you avoid falling into this trap and he suggests the use of an intermediate variable as possible solution. This post was followed by a few which discussed the shortcomings of the tool being used and not one them directly identified the programmer as the primary source of the problem and the coercion properties of String as being the secondary problem.

The programmer intended the method getSField to return a String, when he used the auto-correction feature it was his responsibility to check that the tool created the correct method signature and if it did not, to make any changes necessary. One cannot rationalize leaving the incorrect return type by saying that doing so is doing the minimum necessary to make the test pass. Programming is an intentional act and one cannot set aside intentionality whenever one likes. So the first source of the problem is the programmer not doing what is needed to implement his design.

The secondary problem occurs in this method call: assertEquals("zork", sObj.getSField()). The second parameter being passed to this method is of type Object. Java will select the JUnit assertEquals(Object o1, Object o2) as the one to call. The designers of JUnit use this method as a catchall. In it they use a call like this: o1.equals(o2) and rely on the properties of Java to call the equal method of the passed in type, which in this case is String. The implementers of the String equals method allow an Object to be passed to this method. They then check if the Object can be downcast to String and if so they do the comparison. The problem is that this defeats the runtime type checking of Java to help the programmer achieve his intended design.

The only way to get help from the type checking capabilities of Java is to use a local variable of the intended return type. I suggest that the way to this is to start by writing a test that only checks for a null SField value like this:

    @Test
    public void testNullSField() {
        SObject sObj = new SObject();
        String sField = sObj.getSField();
        assertNull(sField);
     }

This test clearly expresses the intent of the design and uses the Java's type checking to ensure that the return type is what the programmer intended. As well, Eclipse's auto-correction feature will generate a method with intended return type. The use of the local variable should not be factored out as it is there to use the type checking capabilities of Java to help ensure that the design intent for the method getSField is achieved. Now add the test for set by adding a new test like this:

    @Test
    public void testSettingSField() {
        SObject sObj = new SObject();
        sObj.setSField("zork");
        assertEquals("zork", sObj.getSField());
     }

I also acknowledge that Eclipse is not generating the methods as well as one would like. Even if this is improved, one must always keep in mind that auto-correction is a heuristic, a guess, and is therefore fallible and it is the programmer's responsibility to check that the generated code is what was intended.

 

What did you think of this article?




Trackbacks
Trackback specific URL for this entry
  • No trackbacks exist for this entry.
Comments
    • No comments exist for this entry.
Leave a comment

Submitted comments will be subject to moderation before being displayed.

 Enter the above security code (required)

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.