Archive for 2006

Agile India Goa 2005 Distributed Agile Presentation

Thursday, January 12th, 2006

I gave a presentation at XPToronto late last year on distributed agile, and how we went about transforming one of our own projects that had stagnated. This was an interesting project, not least because it is a large (at its peak about 40 developers, 35 in India, 5 in the US) long-running (5 years) agile project.

Goa Presentation - Even More Agile

This is a presentation that Deven Tolia and I gave at and Agile conference in Goa, India in 2005. Originally we did it with 2 projectors, one showing the photographs, and one the slides. We found then, and it was re-inforced when I did it in Toronto, that the photos are the most interesting aprt of the presentation. Many people haven’t seen an Agile project, and talking about theory is no substitute for seeing it done, even if the images are still.

And (re)-reading Tufte’s excellent The Cognitive Style of Powerpoint reinforces the observation that bullet points are not content. The content is in the conversation and the talking that accompanies the pictures, or the whitepaper that expands on the discussion. Deven and I plan to write this paper up in more detail this year, hopefully to present it at one of the Agile conferences this year. When we do that, I hope we will be able to rework it to address those issues.

Assertions on Domain Objects

Monday, January 9th, 2006

Martin Fowler has blogged on a testing technique he calls TestInvariant.

This reminded me of a related approach that I have used is to refactor assertion methods onto the class under test. Here is how I got there.

Suppose you are was writing some tests on Martin’s bowler class:

public void testConcedingRunsAddsToRunsScore() {
  Bowler botham = new Bowler();
  assertEquals(0, botham.getRuns());
  botham.concedeRuns(4);
  assertEquals(4, botham.getRuns());
}

Now there are 2 code smells here to me.

First, the test has forced me to expose the internal implementation of the Bowler class - bleargh. It is bad enough in domain objects and it is worse when it is just for the purpose of testing. Even if we make the getter package protected it still ollutes the API. And sooner or later someone will come along who will make it public and start using it.

Second, the assertions are not very domain specific - and there is duplication. Lots of developers will make them a bit more informative with a message - like this:

public void testConcedingRunsAddsToRunsScore() {
  Bowler botham = new Bowler();
  assertEquals("Should have 0 runs", 0, botham.getRuns());
  botham.concedeRuns(4);
  assertEquals("should have 4 runs", 4, botham.getRuns());
}

I tend not to do this for assertEquals - it is already informative enough, and the message doesn’t increase readability, it increases duplication. So lets do something else:

public void testConcedingRunsAddsToRunsScore() {
  Bowler botham = new Bowler();
  assertHasRuns(botham, 0);
  botham.concedeRuns(4);
  assertHasRuns(botham, 0);
}

private void assertHasRuns(Bowler b, int runs) {
  assertEquals(runs, bowler.getRuns());
}

That’s nice - we have a new informative assertion that is now making an assertion about the domain, not about the state of the object.

If you look at the testConcedingRunsAddsToRunsScore method, everyhting it does is expressed in the language of the domain - we have a mini domain language right here. Consider the assertion assertHasRuns(botham, 0) - that reads nicely.

But now there is one more code smell - feature envy. The assertHasRuns method is envious of the bowler, and following the precepts of refactoring - we should listen to what the code is telling us and move the method onto the bowler. so lets do that:

class Bowler {
  public void shouldHaveRuns(int expectedRuns) {
    Assertion.assertEquals(expectedRuns, this.runs);
  }
}

I’ve done one extra step here, and renamed the assertion to make the domain language a bit clearer. Let’s look at the test now:


public void testConcedingRunsAddsToRunsScore() {
  Bowler botham = new Bowler();
  botham.shouldHaveRuns(0);
  botham.concedeRuns(4);
  botham.shouldHaveRuns(4);
}

There is one extra really nice thing now - since the assertion has moved onto the class under test, we no longer need to expose the getRuns method. So we can remove it and increase the encapsulation of the class.

This approach also fits quite nicely with the emerging approach of Behaviour Driven Development and Humane Interfaces.

Note though that as shown above, you need to distribute the JUnit classes with the production code, to make the assertion methods object available. I don’t mind this. If you do, you could use Java’s own assert support, or move the assertions onto a testing subclass of the original object.

This is a technique that I have used to “re-encapsulate” objects in legacy systems. Often there are objects that give all their information away through getters, initially for testing and then slowly people start using the methods rather than encapulating behaviour. This allows you to remove the getters incrementally.