Archive for the 'Expressive Code' Category

Report of the first run of the OCP kata

Tuesday, February 23rd, 2010

Two weeks ago we had our first meeting of the Milano Coding Dojo. It was great fun, and I was honored to see Giordano had prepared such a good presentation mentioning, among other things, the “OCP Kata” of my earlier blog post. The “Open Closed Principle” says that we should be able to add new feature by adding code, not by changing existing code (with an exception made for the place where the objects are created; after all, for the new class to be used, it must be instantiated somewhere.) The OCP Kata is a set of rules, to be used in a training session, that force us to apply the OCP.

So this was not only the first test-drive of this Dojo, but also of the OCP Kata. How did it go?

We worked randori-style on the Yathzee kata. My impressions follow.

On the OCP Kata rules

The OCP Kata was an influence only for the first test (forced us to use an explicit factory) and the second test (forced us to apply the OCP). After that, the OCP rules did not fire, as the problem was naturally easy to be solved in OCP style. After all, it was the implementation of a series of scoring rules for the Yathzee game. Once you have the scoring rules machinery in place, everything else can be completed just by adding a new class (and modifying the factory).

One class, many uses

We must always keep an eye on the design. The complexity of the code kept going up, until we worked hard at removing duplication. The OCP rules do not produce a good design by themselves. Early in the kata, the rule for “twos” was the same as the rule for “threes” with 3 in place of 2. The solution was to create a SingleNumberRule that takes the number in the constructor. We avoided making two classes, when a single class could be used in different context with different configuration.

The driving force was removing duplication.

More duplication

Later, we had a lot of duplication between the “pair” rule, and the “double pair” rule. The code that looks for a pair is needed in both rules. An old-school OO programmer would have made the two rules derive from a common, abstract base class. The abstract base class would be a repository for shared methods. Modern OO programmers know to use inheritance only as a last resort. So what could we do to remove duplication without inheritance? One key observation was that most of that duplicated code was looking heavily into the array of rolls. When you have code that uses heavily a data structure, it’s a good idea to move both data structure and code in an object.

The natural name for that object is “hand”, so we created a Hand class that wraps the array of die rolls. The duplicated code disappeared.

The driving forces were removing duplication and avoiding direct access to data.

Finding abstractions

The code in the Hand class was still not good enough. It was full of loops. There was no flash of insight here, we just applied a few “extract method”s that moved each loop in its own little method. Once we did that, we realized that some loops depended on another one that counts the occurrences of each number in the hand. For instance, the occurrences in the hand (1, 1, 3, 3, 4) are (2, 0, 2, 1, 0, 0). This is a key abstraction in this domain.

The other abstraction that is needed to implement the pair rule is “find me the highest pair”, which is just max{i | occurrences(i) ≥ 2}. (It is not enough to score *any* pair. It must be the highest pair, if more are present.)

To implement the “double pair” rule, we need a way to say “find the second highest pair”. One way to say this is that if the highest pair is, say, 4, we must look for the highest pair that is less then 4. The method we need is

    public int highestPairLessThen(int n) {
       return max{i | occurrences(i) ≥ 2 && i < n};
    }

Now the two pairs rule was easy to implement:

    public int highestPair() {
      return highestPairLessThen(7);
    }

    public int secondHighestPair() {
      return highestPairLessThen(highestPair());
    }

The solution here was to find the right abstractions, and implement complex things in terms of simple things. It’s a bit of functional programming in the small.

Conclusions

The goal of good design is to have simple building blocks that can be combined together to create complex things. When we are at the object-talking-to-other-objects level, the OCP principles guides us to invent object abstractions. When we are in the small, within-the-object level, it’s good to apply some mathematical thinking. It’s not deep, difficult mathematics. It’s just a game of finding the right definitions, and using them to express complex things in terms of simpler things.

Update: cleaned up HTML, added headings

The OCP kata

Tuesday, January 12th, 2010

Read the first chapter of the Patterns book, it’s all there, where it says “favor composition over inheritance”,

said Jacopo. We were chatting about the Open/Closed Principle, and how I read about it in Meyer in 1991, yet it didn’t “click” for me back then.

Now I see how the OCP is key to writing code that can be changed easily, which is the chief technical goal of an agile team. I wondered, is there a way to teach and learn the OCP? Is there a kata to learn OCP?

It’s unfortunate that most common coding katas result in “single-object-oriented programming”. The famous bowling score example by Robert Martin, for instance, is usually solved by creating *one* object. This might be fine for learning how to write simple code. It’s not so good for learning how to do object-oriented design.

So I invented this little exercise to practice and learn OCP.

Take any coding problem. The bowling score, the string evaluator, the supermarket checkout, you name it. Then follow these instructions.

0. Write the first failing test. Then write a factory that returns an object, or an aggregate of objects, that make the test pass.

The factory should be limited to creating objects and linking them together. No conditionals allowed.

1. Write the next failing test.

2. Can you make it pass by changing the factory and/or creating a new class and nothing else? If yes, great! Go back to 1. If not, refactor until you can.

The refactoring should bring the system to a state where it’s possible to implement the next test just by changing the aggregate of objects that is returned by the factory. Be careful not to implement new functionality; the current test should still fail.

For instance, take the bowling score problem. The first test is

  @Test public void gutterGame() throws Exception {
    BowlingGame game = new BowlingGameFactory().create();
    for (int i=0; i<20; i++) {
      game.roll(0);
    }
    assertEquals(0, game.score());
  }

The code to make this pass is

  class BowlingGameFactory {
    public BowlingGame create() {
      return new BowlingGame();
    }
  }

  class BowlingGame {
    public void roll(int n) {}
    public int score() {
      return 0;
    }
  }

Nothing strange here. Now the second test is

  @Test public void allOnesGame() throws Exception {
    BowlingGame game = new BowlingGameFactory().create();
    for (int i=0; i<20; i++) {
      game.roll(1);
    }
    assertEquals(20, game.score());
  }

The simplest code that makes both tests pass would be to change BowlingGame to accumulate rolls in a variable. But our rules stop us from doing that; we must find a way to implement the new functionality with a new object. I think about it for a few minutes, and all I can think of is to delegate to another object the accumulation of rolls. I will call this role “Rolls”. Cool! This forces me to invent a new design idea. But I must be careful not to add new functionality, so I will just write a Rolls object that always returns 0.

  interface Rolls {
    void add(int n);
    int sum();
  }

  class BowlingGame {
    private final Rolls rolls;

    public BowlingGame(Rolls rolls) {
      this.rolls = rolls;
    }

    public void roll(int n) {
      rolls.add(n);
    }

    public int score() {
      return rolls.sum();
    }
  }

  class BowlingGameFactory {
    public BowlingGame create() {
      Rolls zero = new Rolls() {
        public void add(int n) {}
        public int sum() { return 0; }
      };
      return new BowlingGame(zero);
    }
  }

This passes the first test, and still fails the second. In order to pass the second test, all I have to do is provide a real implementation of Rolls and change the factory.

  class Accumulator implements Rolls {
    void add(int n) { ... }
    int sum() { ... }
  }

  class BowlingGameFactory {
    public BowlingGame create() {
      return new BowlingGame(new Accumulator());
    }
  }

And so on. The point here is to think about how to

  1. compose functionality out of existing objects, and
  2. avoid reworking existing code.

Feedback?

TDD is not finished until the code speaks

Saturday, April 25th, 2009

A problem, and solutions that don’t seem right

I recently asked a few people to solve a little programming problem. In this problem, a number of towns are connected by one-way roads that have different distances. The programmer must write code that answers questions such as:

  • What is the distance of the path A-B-C-D?
  • How many paths are there from A to C that are exactly 4 steps long?
  • What is the distance of the shortest path from A to D?

The graph

I reviewed three different solutions; they were all valid, reasonably well written. Two had proper unit tests, while the third was checked by prints in a "main". The authors tried hard to write a "good" solution. There were no long methods; all the logic was broken down in small methods. And yet, I was not pleased with the results.

(more…)