Archive for April, 2011

Code kata: visualizing crontab using “higher level” TDD

For a number of reasons I had to write a snippet of Java code in my spare time. However, I wanted to learn something new, so I treated it as a code kata, the purpose of which was to discover how well you do if you drive your code using higher level tests. So, instead of using class-level unit tests, I wrote tests that exercised 3-4 classes at the same, thus testing the API at the outermost interfaces. This is what I arrived at (click to enlarge):

Until this point, I’ve either been test-driving code using high-level acceptance tests from a framework like Concordion or FitNesse, or tight unit tests. What made me try something new was Uncle Bob’s Transformation Priority Premise in conjunction with the TDD style presented in the book called “Growing Object-Oriented Software Guided By Tests”. Let me explain:

The way I understand the TPP, it makes us narrow our tests and changes as much as possible. By applying tiny transformations we stay very safe. However, there’s the time factor… How many unit tests do you need/want to write, and do they really feel meaningful, or do they need to be written just for the sake of introducing certain branchings in the code?

As for the book… It has it’ goods and bads (I will review it very soon), but what’s special about it is this style of TDD.

So what did I actually implement in this experiment? A simple parser that understands the standard case of the crontab format “* * * * * <command>”, and that can print it to the screen taking different time scopes into account. While I had to stop somewhere (it was a kata after all), I feel that I have discovered enough to present the conclusions. The first test looked sort of like this:

@Test
public void executableScheduledFirstDayOfEveryMonth() {
    CronCommand command = new CronCommand("runme", new DayOfMonthField(1), new HourField(0), new MinuteField(0));
    ExecutionYear executionYear = new ExecutionYear();
    executionYear.addCommand(command);
    final String expectedOutput = "January\n1\t0:00\trunme\n" +
        "February\n1\t0:00\trunme\n" +
        "March\n1\t0:00\trunme\n" +
        "April\n1\t0:00\trunme\n" +
        "May\n1\t0:00\trunme\n" +
        "June\n1\t0:00\trunme\n" +
        "July\n1\t0:00\trunme\n" +
        "August\n1\t0:00\trunme\n" +
        "September\n1\t0:00\trunme\n" +
        "October\n1\t0:00\trunme\n" +
        "November\n1\t0:00\trunme\n" +
        "December\n1\t0:00\trunme\n";
    assertEquals(expectedOutput, executionYear.outputScope(new YearScope(), new StringOutputFormat()));
}

It’s very verbose, but that’s more a result of the fact that I wanted to go for output immediately. At this point your IDE does a lot of work for you by creating all missing classes and methods. But stop, where did all the class and method names come from? They didn’t come into being through emergent design! No, they did not. I actually spent some time thinking about what the correct API should look like. It did evolve over time, but the fundamental structure still remains.

When implementing the functionality, I tried to write good and correct code that would not need a round of refactoring, i.e., I didn’t evolve the code by duplication elimination. That’s not pure TDD either. Of  course, as tests were added, I followed the methodology and removed duplication and refactored both test and production code.

Another sin I committed was mixing in “test-last”. On the whole I relied on the high level tests, but when working with logic I felt uncertain about, I added unit tests until I felt secure again. Since I kept the code very clean with extremely short methods, not many additional tests were required.

The image above shows the coverage I reached using the method, and I think it’s as good as it gets. (Not that coverage says anything about quality, but it shows that no code has been added without being driven by tests).

I guess this technique isn’t controversial for many people, but for me it was. I’ve been stuck doing TDD that’s close to TPP, and I’ve always had to struggle with code locked down by unit tests and package-access methods. This way of working feels very intuitive, and I will definitely explore it further. To sum up:

  1. Come up with a rough design. Think for a while.
  2. Write a high-level test that captures the essence of that design and verifies the API.
  3. Make the test pass, and don’t be stupid about it. Implement the solution well, but without any bells and whistles.
  4. Add another high-level test that captures another aspect of the functionality.
  5. Make it pass, and refactor your existing production and test code.
  6. If you feel uncertain about some logic or boundary conditions, add unit tests that secure that part of the code.
  7. Iterate between steps 4-6.

No Comments

Logical code

logicWhile reading a book on unit testing, The Art Of Unit Testing by Roy Osherove (a very good book by the way), I stumbled across his definition of “Logical code”:

Logical code is any piece of code that has any logic in it, small as it may be. It’s logical code if it has one or more of the following: an IF statement,  a loop, switch or case statements, calculations, or any other type of decision-making code.

Why is this definition important? In my world it replaces “too simple to break”, which I think comes from another (old) book on unit testing. If you google it, you realize that it’s not a commonly accepted term for code that needs tests. Simple and trivial as this term might be. I still think it needs more recognition, acceptance, and use. It is, after all, a very sharp and clean definition of an elusive concept.

The world would be a nicer place if conversations like this could take place:

(Good devloper): Why haven’t you written a unit test for this method?

(Bad developer): It’s too simple to introduce any errors. Don’t sweat.

(Good devloper): It does a calculation, therefore it’s logical code. Start working!

No Comments

Most accidental complexity using least cyclomatic complexity

When I first saw this I knew it broke som kind of record. I’d say the code below manages to max the ratio accidental complexity / cyclomatic complexity. And yes, it does contain a bug too… And yes, iterator.remove() was available when this was conceived.
As always, I’ve renamed a few things to make the hide the source. “Entity” has a more descriptive name in the real code.

private void addEntityToSession(Entity ppto, HttpServletRequest request) {
     // Create an entity object to set as an attribute in the session
     EntityAdapter entity = new EntityAdapter(ppto);

     // Set the entity attribute in the session
     request.getSession().setAttribute("entity", entity);

     // Creates an array in which entities will be placed and displayed in a dropdownlist
     ArrayList historyArray = ((ArrayList) request.getSession().getAttribute("history"));

     if (historyArray != null) {

         // Removes the entity at position number 10 in historyArray
         if (historyArray.size() == 10) {
             historyArray.remove(9);
         }

         Collection tmpList = new ArrayList();

         // Looping through the historyArray and places any entity that are  equal to the
         // one the will be added
         for (Object aHistoryArray : historyArray) {
             if (((EntityAdapter) aHistoryArray).getId() == entity.getId()) {
                 tmpList.add(aHistoryArray);
             }
         }

         // Looping through the historyArray and removes entities that were added above in tmpList
         for (Object aTmpList : tmpList) {
             historyArray.remove(aTmpList);
         }
         historyArray.add(0, entities);
     }
}

2 Comments