The OCP kata

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?

Updates

24/12/2013 Chris F Carroll‘s Gilded Mall Kata is a new exercise that can be done with the OCP kata rules. Thanks Chris!

29/05/2014 There is now a repository with a few prepared exercises! I presented this at XP2014.

17 Responses to “The OCP kata”

  1. Franco Lombardo Says:

    Matteo,

    good exercise: we must do it at XP UG Milan! :-)

    Now some notes. You say
    “1. compose functionality out of existing objects”: that’s OK.

    “2. avoid reworking existing code”: please, could you explain this? I mean, in your example, at each step you do need to modify some part of the existing code: the BowlingGameFactory, the BowlingGame…
    To be honest, in the Open Close Principle what I don’t believe in is the “Close” part. Meyer, in it’s original book, thought to implement it mainly via inheritance. But, as in the beginning of your post, “favor composition over inheritance” it’s a good rule!
    To use composition, you must have designed some “injection” point for new behaviors: in your example, the Rolls interface could contain new behaviors, but you need to modify all your classes to accept this injection. Now your code is “closed” to change in this direction, but as soon as new change directions will arise, probably you will need to rework the existing codebase.

    Thanks

    Bye

    Franco

  2. matteo Says:

    Hi Franco, thanks for your feedback :)

    First let me say that this is an exercise, and it’s focused on one single aspect of OOD, namely the OCP. I’m not saying we should work like this all the time :-)

    Now, let me clarify the “not reworking” thing. In an ideal world, I should be able to accept a new requirement by creating a new class, and injecting it in the system by changing the “main” or the “factory” of the system. It would be even better if I could add new behaviour simply by configuring and instantiating existing objects.

    For instance, take the bowling example. If you have all your scoring rules in a chain of responsibility, you could add the “strike” scoring rule by creating a new StrikeScoreRule class and injecting the object in the system:

    BowlingGame create() {
    Rolls rolls = new Rolls();
    List rules = Arrays.asList(
    new StrikeRule(rolls),
    new SpareRule(rolls),
    new SumOfTwoRollsRule(rolls));

    return new BowlingGame(rolls, rules);
    }

    Suppose now that they ask you to implement “Martian Bowling”, where you have a maximum of three rolls per frame. You might implement it by creating a SumOfThreeRolls class, and changing the factory like this:

    BowlingGame create() {
    Rolls rolls = new Rolls();
    List rules = Arrays.asList(
    new StrikeRule(rolls),
    new SpareRule(rolls),
    new SumOfThreeRollsRule(rolls));

    return new BowlingGame(rolls, rules);
    }

    or you might have a flexible object that can act as both the SumOfTwoRollsRule or the SumOfThreeRollsRule like this:

    BowlingGame create() {
    Rolls rolls = new Rolls();
    List rules = Arrays.asList(
    new StrikeRule(rolls),
    new SpareRule(rolls),
    new SumOfSomeRollsRule(3, rolls));

    return new BowlingGame(rolls, rules);
    }

    Now you ask, what if I am not living in an ideal world, and I cannot simply add new behaviour without reworking everything? And this is the common case! In my opinion, what you could do then is to first refactor everything *as if* you had foreseen the new requirement. You refactor until you can apply the OCP. Then you insert the new requirement, and it just “slides in” like magic.

    I think it’s even better to wait until you have an actual requirement, before you make everything super-flexible. Otherwise you run the risk of making everything too flexible, that is, to over-engineer.

  3. Giordano Scalzo's Personal Blog » Milano XpUg January Coding Dojo Says:

    […] As introduction I prepared a little presentation, mainly with the aim to clarify the “Ocp Way” to do katas, as conceived by Matteo Vaccari in his blog: XpUg Coding Dojo: KataYahtzee in […]

  4. 84° Extreme Programming User Group di Milano | Geek Agenda Says:

    […] Randori: a coppie ci si alternerà al proiettore per risolvere un semplice problema, in modalità OCP; non è obbligatorio partecipare alla coding session,ma si può semplicemente assistere allo […]

  5. Extreme Enthusiasm » Blog Archive » Report of the first run of the OCP kata Says:

    […] 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 […]

  6. Tonyx Says:

    Ciao Matteo,
    there is an implementation in c#:
    http://github.com/tonyx/katabowling

    Ciao.

  7. Extreme Enthusiasm » Blog Archive » The Rock-Scissors-Paper OCP Dojo Says:

    […] kata was meant to be executed with the OCP Dojo rules. I will use Ruby today, because I want to take a break from Java. But the solution will not […]

  8. Extreme Enthusiasm » Blog Archive » On discussions Says:

    […] I have not become convinced that iterative development, small steps, refactoring are to be avoided. I’m not advocating doing some big upfront design to make sure we can hit the release code without iterating, without incrementing functionality bit by bit, without refactoring. I still think that iterative and incremental design is the only reliable way to produce good software. But we must remember that refactoring per se is waste. Francesco Cirillo is fond of saying that emergent design is not “doing some messy work now, then I will refactor”. It’s more efficient to write incremental code that can be extended without refactoring; it’s more efficient to exploit the Open-Closed Principle! […]

  9. Extreme Enthusiasm » Blog Archive » November is busy :-) Says:

    […] Days Benelux, November 25. Together with Antonio Carpentieri I will present a workshop on the Open-Closed Principle Dojo. It’s a way to learn an important principle of object-oriented […]

  10. Extreme Enthusiasm » Blog Archive » The OCP kata « ZenAndSoftwareDevelopment Says:

    […] Extreme Enthusiasm » Blog Archive » The OCP kata. Pagine […]

  11. Franco Lombardo » Blog Archive » Italian Agile Day 2010 Says:

    […] dell'XP User Group di Bergamo abbiamo provato a rifare il Kata "Sasso-forbici-carta" seguendo le regole "Aperto-chiuso" suggerite da Matteo Vaccari. Il pubblico non era certo numeroso…ehm…ehm…vabbe', se vi interessa qui sono le slides e […]

  12. Mini XP Day 2011 « Legacy Code Public Enemy Says:

    […] In December me and Matteo Vaccari have presented the The Open-Closed Principle Dojo based on his OCP Kata. […]

  13. Just playing with Open Closed principle | Roberto Mereghetti Says:

    […] Just playing with Open Closed principle Share this:TwitterFacebookMi piace:Mi piace Caricamento… […]

  14. Code kata 6: The classic bowling game scorer, open and closed | Red Gate Software Development Says:

    […] the open to extension and closed to modification, we’re going to follow the workflow described at http://matteo.vaccari.name/blog/archives/293. This is how it […]

  15. Johan Martinsson Says:

    Follow to the conversation on twitter https://twitter.com/xpmatteo/status/747305326618148864

    Say I have implemented the normal accumulating bowling score and I write a test for strike.
    It seems that making the test pass with a conditional like this is contrary to the rules.

    if (rolls[0] === 10) {
    score = sumOf3Rolls(rolls)
    } else {
    score = sumOf2Rolls(rolls)
    }

    However if I refactor right after the result is (probably) the same. And to me there are several advantages to this “refactor after” approach.

    The advantages of “refactor after” are to me
    – compliant to Make it work then Make it good
    – easier (ok that’s a bad argument for a kata)
    – builds a habit of looking at manifest mess before refactoring -> likely to lead to simpler design

    So my question is what will people gain from doing it in the “refactor before” way? I tried it for quite a bit, didn’t get much from it but I suspect I might be missing something here.

  16. matteo Says:

    The “refactor before” rule of the OCP Dojo is a trick, to force the learner to think about why a certain extension of behaviour is not possible with the current code. This dojo is all about pushing the abstraction pedal as far as possible. Someone said that the only way to know when something is “too much”, is to do it too much!

    So yes, in Real Work sometimes you complicate the code a bit, and then refactor. Some other times, when you find that implementing something is difficult, you first make it easier by refactoring (which might be difficult to do), and then you do it.

    In a dojo context, however, if the goal is to practice creating abstractions, the rule about creating it before use is meant to force a behaviour. If you intend to create it after, you run the risk of rushing to making the next test pass, and forget to introduce the abstraction at all. So I think it can be OK to be flexible about introducing the abstraction after you need it, as long as you have a watchful moderator that will remind the learners to implement the abstractions!

    Is that any clearer? I mean, the exercise is meant to help people who aren’t used to creating abstractions. If your audience has the opposite problem, then you might do better with another exercise, like e.g., the TDD As If You Meant It by Keith Braithwaite

  17. Johan Martinsson Says:

    Your answer is clear. I’ll try more times for my own benefit. I also project using this dojos in training teams, and I’m much more hesitant. I do see there’s probably and muscle training that is a bit different and perhaps more acute. The possible downsides to me as a training tool are

    – Few people allow themselves to write shitty code first, and it is such an efficient design tool. This is for instance a major difficulty in learning TDD – allowing yourself to just make the test pass, and quickly
    – I want them to have a tool that is readily available immediately (well mostly) and the ability to refactor “after” towards OCP is easier to learn.

    Maybe which approach is best depends on the person doing it, so “refactor before” could be an optional constraint. The base constraint being to refactor before next test.

Leave a Reply