Written by Harry Roberts on CSS Wizardry.
In my work, I tend to get involved in a lot of refactoring projects. From small-scale tweaks of work-in-progress frameworks or styleguides, right through to full-scale refactors of years-old legacy projects. In fact, I do so much work with clients who need to refactor that I spent much of 2016 speaking about it.
There are many interesting things about refactoring—from technical to logistical to cultural—but two points that are most relevant to this article are:
get it right this time. This can feel debilitating:
Where do I start?
How long is this going to take?
How will I know if I’m doing the right thing?
A concept I came up with to help my clients and their teams tackle these two problems was the idea of a Refactoring Tunnel.
A Refactoring Tunnel is a metaphor in which the length or size of the refactoring task is represented by a tunnel of a corresponding size: long tunnels represent large refactoring tasks; short tunnels represent small ones.
A more developer oriented way of looking at or defining the size of a refactoring task might be to describe its surface area: how much of the codebase does the body of work touch?
The Refactoring Tunnel metaphor works like this:
On day one, you pick your refactoring task: you step into the tunnel. At this point, you can see the light at the tunnel’s entrance behind you, but you can’t see the light at the exit—perhaps it’s close but around a sharp bend, or maybe it is just that far away. At this point, we don’t know, but it doesn’t concern us because we have only just started.
Day two: we continue working on our refactoring task, and proceed further into the tunnel. Just like yesterday, we can still see the light at the entrance behind us, but the light at the exit still evades us. That is to say, we have a good idea of where we’ve come from, but still don’t know how far away the exit is: is it another week? Two weeks? Three days?
We press on, day after day making our way further into the tunnel, until day nine. All of a sudden, the light behind us has disappeared. We know we did nine days of work, but we’ve now lost the security of being able to see a fixed point behind us.
To compound the problem, we still can’t see the light at the exit either. The
panic sets in; we’re lost. The site is broken around our feet. The
find-and-replace for the class names didn’t work as we’d hoped, and now some
sure why. We’ve tried to keep merging
master into our topic branch, but we see
more and more merge conflicts. And we still have no idea where the exit is. Is
it quite close? Would it be worth continuing another day or so? Or is it still
many days—or even weeks—away from us? We have no way of knowing. The uncertainty
is stressful; it is a gamble. We begin to wish we’d never started, and in total
desperation, we do this:
$ git reset --hard origin/master
We just throw everything away. We hard reset ourselves to a point in time we knew to be safe—and we do begin to feel safer again—but we have to face up to the fact that we just spent nine days of time and money getting to precisely nowhere. That’s going to be a difficult one to explain at your stand up, and will likely reduce the chances of the business trusting developers with refactoring time in future.
I’ve done this, and seen it done, more times than I would care to remember (or admit). I’m sure you’ve done it at some point as well. This is the danger of entering long Refactoring Tunnels.
Tasks with a large surface area—and thus, a long tunnel—might be things like
While each of these may be worthy and worthwhile changes to make, they’re relatively large. They will affect and modify the entire project’s codebase, which means a few things:
Don’t enter a tunnel whose end you can’t see, or that you can’t exit from quickly and cheaply.
Resist the temptation to refactor anything that runs right the way throughout the project. Instead, identify smaller and more manageable tasks: tasks that have a much smaller surface area, and therefore a much shorter Refactoring Tunnel.
These tasks can still aim toward a larger and more total goal but can be realised in much safer and shorter timeframes. Want to move all of your classes from BEM to BEM(IT)? Sure, but maybe just implement it on the nav first. Attacking the problem this way has many benefits:
Your overall goals for the project can remain the same but try to identify and isolate the sub-tasks into much smaller and safer units. Make sure you only ever step into short tunnels.
I firmly believe that the user will ultimately benefit from a refactored codebase, but in ways that are hard to actually measure. ↩
Hi there, I’m Harry Roberts. I am an award-winning Consultant Web Performance Engineer, designer, developer, writer, and speaker from the UK. I write, Tweet, speak, and share code about measuring and improving site-speed. You should hire me.
You can now find me on Mastodon.
I am available for hire to consult, advise, and develop with passionate product teams across the globe.
I specialise in large, product-based projects where performance, scalability, and maintainability are paramount.