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
- compose functionality out of existing objects, and
- avoid reworking existing code.
Feedback?

January 15th, 2010 at 10:10
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
January 18th, 2010 at 19:19
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() { rules = Arrays.asList(
Rolls rolls = new Rolls();
List
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() { rules = Arrays.asList(
Rolls rolls = new Rolls();
List
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() { rules = Arrays.asList(
Rolls rolls = new Rolls();
List
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.
February 6th, 2010 at 16:16
[...] 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 [...]
February 21st, 2010 at 15:15
[...] 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 [...]
February 23rd, 2010 at 21:21
[...] 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 [...]
March 2nd, 2010 at 1:01
Ciao Matteo,
there is an implementation in c#:
http://github.com/tonyx/katabowling
Ciao.