This is a general refactoring strategy for completing a larger change in small steps.
Mark the true statements and not the other ones:
Ask people in particular about their answers to question 3. Why shouldn’t the code be broken for days? What would happen if it was? Have you experienced this?
One approach to break a refactoring into small safe steps is “parallel change” (also known as expand, migrate, contract). Parallel change could be compared to a road construction site. No one would tear down an existing bridge and redirect traffic through the valley during construction. Normally you would construct the new bridge before the old one is removed.
In software we have the ability to grow things incrementally. So we can build a new bridge starting with a tiny one where we can divert the pedestrians, then the cars, then the trams and later the trains. It is important here that as soon as we divert the cars to the new bridge, we also remove the road for them from the old one. In this way the new bridge is being built bit by bit while at the same time the old bridge is being dismantled bit by bit but the traffic continues to flow.
Reference - Danilo Sato has published an article explaining Parallel Change.
Ask everyone to take a look at this code: Bingo Refactoring Kata. What code smells do they see (regardless of whether they can name them or not)? What would be a better structure?
You are hoping they will spot that there are data clumps and Primitive Obsession - in particular these primitives:
String[][] cells
boolean[][] marked
These fields are always written and read in common so there could be a data structure encapsulating both the name attribute (String) and the marked
attribute (boolean). Refactoring to a Cell[][]
could be the first step (and this is usually achievable during one learning hour). A further refactoring could be to move a more convenient data structure - instead of Cell[][]
you could have a Map with Coordinate
as key and Cell
as value.
The group might also suggest some other refactorings - methods that could be broken down to smaller private methods, or replace conditionals with polymorphism (e.g. UninitializedBoard/InitializedBoard/…). Ask them to leave those refactorings for a future learning hour, today we focus on Parallel Change and removing the Primitive Obsession.
Show them that you are introducing the new structure without removing the old one. Change at least one write access, maybe there is even a read access which you can redirect to the new data structure at this early stage.
Now, as an exercise, have them start the refactoring again from the beginning and let them do it til the end where the old data structure gets removed.
If they finish that refactoring quickly, you could ask them to use Parallel Change again to convert the Cell[][]
to a Map<Coordinate, Cell>
- an alternate datastructure that removes the primitive obsession on the (x, y) grid co-ordinates.
While the first parallel change focuses on swapping the internal data structure (introducing Cell[][]
), this next one (introducing Coordinate and using it as parameter type) would affect the API (method signature) and so we have external dependencies on the “old” API which we should preserve in parallel with the new one. In a real system you’d use Parallel Change to eventually remove the “old” API once all the clients were migrated to the new one.
Why should you use it: What is the most important aspect for you about “parallel change”?
This learning hour was first published elsewhere: Parallel Change