Code should grow by addition rather than mutation.
This axiom clicked for me after reading an example in Beck’s Implementation patterns. What goes next is almost an exact reproduction of the book. Give the book a read if you want to dig deeper.
Imagine a GraphicEditor
codebase where one of the main abstractions is the Figure
, which has methods like display()
. If you want to support several figures in the editor, you could write a conditional like this:
public void display() {
switch (getType()) {
case RECTANGLE :
//...
break;
case OVAL :
//...
break;
case TEXT :
//...
break;
default :
break;
}
}
How do we add a new kind of figure?
By adding a new case
statement in the Figure
‘s code. And by doing the same in every other switch
across the codebase. It’s tedious work and error-prone: it modifies a working functionality, putting it at risk. You also need to understand the whole picture (where’s other conditionals I should change?) and coordinate with other people that may be working in the same code.
How do we make this code growth by addition rather than mutation? Two of the available tools are inheritance (classes) and delegation (interfaces):

Using one or another is a matter of context. Rewriting the display method to use delegation looks like this:
public void display() {
getType().display();
}
It delegates the implementation of displaying to the rectangle and any other registered figure.
This mechanism makes adding new kind of figures easier: it only requires implementing the Figure
interface and register it so it’s available in the GraphicEditor
. No need to change the existent code, no coordination costs, no need to understand the whole picture before making any change. That’s the power of designing for growth: managing complexity.
Leave a Reply