What is refactoring? Like most of the technical agile practices, seeing the final code doesn’t help. That’s because refactoring is a process; it’s hard to grasp until you see someone do it.
So I gave this 27-minute talk showing what real refactoring can look like for iOS developers. You’ll see several refactoring practices in action that I follow mechanically, without thinking much.
In the talk, I take a view controller using Model-View-Controller (MVC) and begin refactoring it to Model-View-ViewModel (MVVM). The view controller has unit tests and is based on real iOS code I wrote for eBay.
The talk begins the refactoring to MVVM but doesn’t complete the transformation. I show the rest of the journey in a second video In a third video, I show how to refactor to the Null Object pattern.
Thank you to CocoaHeads NL for inviting me to speak, and for producing the video.
The Importance of Unit Tests
The view controller behavior is covered by unit tests. These tests provide the fast feedback we need to take small steps, verifying each step.
While MVVM can make it easier to write tests, in this refactoring the view model is an implementation detail. The tests are already written and don’t care how the work gets done, as long as it gets done.
After each step, I do one of two things: build and test, or just build. I could run tests each time—and often do in the demo. But when I add new code that isn’t called yet, just building is enough feedback.
Notice how often I build or run tests, to get feedback on my latest step. The faster the feedback, the smaller the steps can be.
For Refactoring, Stay in Green
When refactoring, start in green (meaning tests pass), and end in green. Try not to go through red (build failing or tests failing).
If you do go into red, get back to green as quickly as you can. If you stay in red for more than a couple of minutes, it’s probably time to revert and start over from green. This is a technique Adrian Bolboaca calls “taking baby steps.”
We discussed today of pros and cons of Taking Baby Steps. It can be related to the recent discussions about #TCR and #TDD. #Refactoring #Workshop /w @mozaicworks pic.twitter.com/A8Q3FUn4Rf
— Adrian Bolboaca (@adibolb) December 4, 2018
Parallel Change
Parallel Change is a common pattern that occurs in many refactorings. I think of this as “lay down the new tracks, switch over to them, then remove the old tracks.” Dave Farley calls it Expand-Shift-Contract:
Expand
Create a new home for some existing functionality. Nothing is calling it yet.
Shift
One at a time, switch old call sites to call the new code.
Contract
After everything has shifted, delete the old code.
After Expand, the code should still build. After each Shift, the tests should still pass. Then after Contract, tests should continue to pass.
Make Similar Expressions Identical
Another pattern that comes up is to take two lines that use similar expressions and make them identical. There are different techniques for this. In this demo, it happens by using a new method that is more general and can handle more situations.
Making the expressions identical paves the way for more interesting refactorings. In my demo, here’s what comes next…
Lift Out of Conditional
We have a conditional, with one expression on the if-side and another on the else-side. But now that we’ve made the lines identical, we can lift them out of the conditional. This works as long as it’s okay for the line to execute before the conditional check.
For example, let’s say we have:
if condition {
x = makeResult()
// More if stuff
} else {
x = makeResult()
// More else stuff
}As long as there is no coupling between condition and x = makeResult(), we can lift those lines out of the conditional:
x = makeResult()
if condition {
// More if stuff
} else {
// More else stuff
}This is a version of the Slide Statements refactoring. It shrinks the body of the if-else clauses. The statement sliding changes the order of the statements, so this isn’t one of the provable refactorings. But as long as the condition is unaffected by the change, unit tests will continue to pass.
One Refactoring Leads to More
As you can see, one refactoring can lead to more refactoring possibilities. And those new possibilities can be hard to picture until they’re the next step. For me, refactoring often happens like this:
This happens to me over and over.
Working in Very Small Steps
Small steps bring advantages:
Fast turnaround time to build and test is essential for working in small steps. That's not a disadvantage! It’s a forcing factor which will help everybody on your team.
Books to Help You
I have two book recommendations around refactoring.
The first is Martin Fowler’s classic Refactoring (that’s an Amazon affiliate link), which he updated in 2019. This continues to be a book I keep in arm’s reach while I work.
The other is my book iOS Unit Testing by Example. Part III of the book shows what unit testing makes possible. There are step-by-step examples of refactoring a view controller.
In a follow-up video, let’s finish refactoring this view controller to MVVM.
All Articles in this series


