| XP123 → Games → Refactoring Grid |
This toy is designed to give you a feel for what refactoring is like, by working in a simple, non-code 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.
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.
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:
|
|
|
|
|
|
|
|
|
|
|
xx |
|
|
oo |
|
||
|
|
|||||||
|
|
|
|
x |
|
|
|
|
|
o |
|
x |
|
|
|
||
Here's a grid that is "smell-free":
|
o |
|
|
|
|
|
o |
o |
|
|
|
o |
o |
|
|
||
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
It's not enough to know smells; to do anything about them we need transformation rules (refactorings).
V1x.
|
|
|
|
|
|
|
|
|
|
x |
|
|
|
|
↔ |
|
|
|
|
|
|
|
|
|
|
x |
|
|
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.
|
|
|
|
|
x |
|
|
|
|
|
|
|
|
|
↔ |
|
|
|
|
x |
|
|
|
|
|
|
|
|
V3x.
|
|
|
|
x |
|
|
|
|
|
|
|
|
|
|
↔ |
|
|
|
x |
|
|
|
|
|
|
|
|
|
V4x.
|
|
|
|
|
|
|
|
|
x |
|
|
|
|
|
↔ |
|
|
|
|
|
|
|
|
|
x |
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
xx |
|
|
oo |
|
||
|
|
|||||||
|
|
|
|
x |
|
|
|
|
|
o |
|
x |
|
|
|
||
to this:
|
|
|
|
x |
|
|
|
|
|
o |
xx |
x |
|
oo |
|
||
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
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.)
Pxo.
|
xo |
↔ |
|
(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.
|
|
|
|
o |
|
|
|
|
|
|
xx |
|
|
oo |
|
||
|
|
|||||||
|
|
|
|
x |
|
|
|
|
|
o |
o |
x |
|
xxx |
|
||
B. What smells can you eliminate?
P1xx.
|
|
|
↔ |
|
x |
|
|
xx |
|
|
P2xx.
|
|
xx |
↔ |
x |
|
|
|
|
|
|
P3xx.
|
xx |
|
↔ |
|
|
|
|
|
x |
|
Rules P1oo, P2oo, and P3oo are the corresponding rules for
"o" tokens.
H24x.
|
|
↔ |
|
(This rule applies to any two horizontally adjacent
windows.)
Rule H24o is the corresponding rule for "o" tokens.
Here are a couple examples:
Example 1.
|
|
→ V2x |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||