The refactoring grid is a toy designed to give you a feel for what refactoring is like, by working in a simple, non-code domain.
[Michael Wainer has made game pieces available here: http://www.cs.siu.edu/~wainer/Pieces4RefGame/pieces4RefGame.html ]
The Domain
There is a grid of “windows,” like this:
Each square in a window is known as a “pane.” Each pane can contain “tokens”; we’ll use two types, represented as “o” and “x.” A pane can contain any number of tokens. There are refactorings that define how tokens can be added, removed, or moved between panes.
Smells
To refactor, you need a sense of when your system needs improvement.
When there are problems that we can name, we call those “code smells.” A goal of refactoring is to eliminate (or at least minimize) the smells.
Here are four smells that can happen in this system:
- Basement – there are any tokens in the lower row of windows.
- Duplication – two of the same token occur in any pane.
- Conflict – the grid contains both an “x” token and an “o” token (in any panes of any windows).
- Sou’wester – any window has a token in the lower-left corner, and another token in either the upper-left or upper-right corner.
Here’s a grid that demonstrates each of these smells:
Here’s a grid that is “smell-free”:
Refactorings
It’s not enough to know smells; to do anything about them we need transformation rules (refactorings).
Vertical refactorings
V1x.
This rule should be read: “If you see two windows stacked vertically, you can move an x from the pane in the lower right corner to the corresponding pane in the upper window, or vice versa.” (The shading is just to highlight the cells involved in the rule, and has no other significance.)
V2x.
V3x.
V4x.
There are corresponding rules V1o, V2o, V3o, and V4o to move “o” tokens.
Exercise 1.
Try your hand at this refactoring. One step at a time, convert this:
to this:
You’ve probably noticed that it’s pretty tedious to move things vertically one at a time. For repetitive refactorings, you may be comfortable taking shortcuts after you’ve done them a few times. (The same thing happens in code. For example, suppose you’re changing the name of something; you might change the first couple carefully, run tests, and then change all the others in one go, without running tests until the end.)
The vertical refactorings are tedious; give yourself permission to do them all at once. (You could call this shortcut rule Vx or Vo).
Exercise 2.
A unit test will be a rule that you can apply to the before and after states to reassure you that a grid has been refactored correctly. What unit test could reassure you that you’ve applied a group of vertical refactorings correctly? (Hint: there’s something true about the grid that is true before and after each of the vertical rules.)
One-pane refactorings
Pxo.
(There’s no order implied; “ox” = “xo”. The rule says that an “x” and “o” token in the same pane cancel each other out.)
Exercise 3.
A. Remove as many smells as you can with the refactorings you have so far.
B. What smells can you eliminate?
One-window refactorings
P1xx.
P2xx.
P3xx.
Rules P1oo, P2oo, and P3oo are the corresponding rules for “o” tokens.
Horizontal refactoring
H24x.
(This rule applies to any two horizontally adjacent windows.)
Rule H24o is the corresponding rule for “o” tokens.
Examples
Here are a couple examples:
Example 1.
Example 2.
Exercises
Here are some more exercises for you to try. Eliminate all smells.
Exercise 4.
Exercise 5.
Exercise 6.
Exercise 7. Do it yourself.
Debrief
Work through the exercises before you try these questions.
- Can you detect all the smells right away? Does fixing one smell make you aware of others? (How is this like programming?)
- What is your strategy for addressing smells?
- Can you design a strategy where once you’ve “fixed” a window, you don’t have to touch it again? Can you do this for code?
- Some of the smells are very local; others are more diffuse. How can you detect smells that span several areas of a system?
- Can any grid be transformed into one with no smells? What about any code?
- The H24x and H24o refactorings only fix part of the “Sou’wester” smell; define shortcut transformations that address the rest.
- These refactorings don’t come with tests; can you devise a test that you can apply to the initial and final states to reassure you that a grid has been refactored correctly?
- Just for fun, you could try one of these approaches to creating different sets of smells or rules:
- Create an aesthetic that will clear every box except the lower right pane of the lower right window.
- Stop worrying about the “Sou’Wester” smell. Drop rule H24x and add rule P4xx instead. Is the system as a whole simpler?
Rule P4xx.
- The “conflict” smell is global. Experiment with more local versions of the smell that still encourage you to apply rule Pxo but allow you to have both “x” and “o” tokens in the same grid.
[Written December 8, 2002. Thanks to Steve Wake for feedback. Correction from Shibukawa Yoshiki, 3-13-03. Updated images and added link to Michael Wainer’s work, Oct. ’09.]