The triggering events for refactoring vary, but the reason we refactor at all is the same each time, regardless of occasion: we refactor to enable change.
The most obvious and direct occasion for a refactoring is this: I want to add new functionality and preserve old functionality, and it will be easier to add if I first schmoosh the old functionality around a little to make a little hole where the new stuff will fit.
When I do this, I usually could make the same change without refactoring first. But I don’t. Why? Because the schmoosh+add takes less time than just add.
This is analagous to the kind of behavior often called "axe-sharpening". A probably apocryphal Lincoln quote goes: "Give me six hours to chop down a tree, and I’ll spend the first four sharpening the axe."
Of course, in this case, we’re not sharpening the axe exactly, we’re, idunno, thinning the tree-trunk. 🙂
No matter, I’m sure you grasp the concept: many operations can be broken into two parts, one of which makes the other substantially easier.
This direct kind of occasion is lovely, because of its simple logic, its easy analogue, and its ready demonstration in lots and lots of coding situations.
But if I stop there, only ever refactoring when I have a clearcut axe-sharpening to do, I am limiting my productivity.
Every other refactoring occasion is — implicitly or explicitly — justified by that direct occasion. To make my case, let me throw another occasion at you and show how it relates.
I often refactor because I do not understand what I am looking at. The chain back to the direct case is less obvious, but it’s still there.
If I don’t understand the old functionality, I don’t even know where to begin to make that hole that will fit the new functionality, right? I am refactoring here not to make that hole directly, but to make an understanding that lets me imagine how to make that hole.
We start with one operation "add new function". We turn it in the direct occasion to "schmoosh+add". In this case, we do it again, turning it to "grasp+schmoosh+add".
Is the three-step faster than the two-step faster than the one-step? My answer to this question is a guarded "yes, as a broadly applicable general rule".
(Please don’t cite to me the cases where the general rule doesn’t cover. I am familiar with them, and I am not providing a judgment-less rule for how I or anyone else should proceed. I’m sorry if that’s driving too defensively, but I got history here.)
Let’s go even further. In addition to the direct case and the grasping case, I will open the floodgates: I refactor habitually, as a matter of course, as soon as I notice any kind of latent "ungraspability" in what I am writing that I have the capacity to schmoose right then.
This isn’t even a pre-step to adding new functionality. It’s actually either a post-step to having added it last time, or even an act I undertake while I’m still adding it.
Out of hand, yeah? This bozo refactors before he even has a need to make a hole!
I am telling you as directly as possible: I refactor code all the time for no other reason than that I do not like the looks of what’s there.
(Notice: we slide here into words like "beautiful" and "clean", both of which I dislike, one of which I gravely mistrust. That’s okay, though, I think we’re all pointing at the same thing, the result of experience and judgment and intuition, what Alexander called QWAN.)
Why? Have I found mystic truth? Did I eat moldy bread and am now having an episode of St. Dijkstra’s Dance? Why would a person just voluntarily make changes to code when she does not have to change it to add new functionality?
It’s a bet. It’s actually three bets. I am making three bets when I do that. I continue to do it because those three bets — they are gambles, not sure things — those three bets consistently make me more money than they lose me.
Bet: There will be a need to change this code.
Bet: It’s cheaper to make it graspable now than it will be later.
Bet: My spidey-sense for what is hard-to-grasp is reliable.
A.J. Leibling said at one point that he wrote better than anyone who wrote faster, and he wrote faster than anyone who wrote better. That’s what I aspire to in code. Making those bets all day long seems to be helping me get there.
A final note: I’m hoping you’ll see that this analysis comes from the way the modern synthesis expands our focus past the made onto the making and the makers. Those three bets have little to do with the made except in terms of how quickly its value ships.
Anyway, I hope your Friday surprises you in a warm pleasing way.