It happens that there are sometimes very complex changes you want to make to your code. These might involve changes to dozens of existing classes, and to the heirs of some of those, too.
How do we approach this kind of situation?
Recall that managing mental scope is the very heart of programming well. But any such change is sure to blow all hope of narrow mental scope right out of the water.
We can only manage mental scope if we apply our change in steps, where each step is itself of small enough scope to be manageable.
To make this work, we need to keep our program running and running green the entire time we’re applying steps. Think of "running green" as the definition of a step boundary. If we’re running green, we’re between steps. If we’re not, we’re inside one. We want to convert our huge change to a series of small green-to-green steps.
Formal refactoring is definitionally green-to-green. Refactoring is changing the design w/o changing the function. So any of the standard formal refactorings we need to apply just automatically qualify.
In addition, any actual re-writing we need in there has to meet the same criteria.
Here’s what I do. In fact, I’m doing it as we speak, or stalling artfully in any case.
Check out head. Randomly go nuts making your crazy complex change. DO NOT COMMIT OR PUSH. Press on for a while.
What you’re going to see is what we call "blood in the gutters". That’s an IDE-user’s term. It means all the red-bar lining the code screen. If you don’t use an IDE — you ought to — think of it as one of those 10,000 error outputs one gets when one breaks the entire free world. But a great many of those errors are repeat errors. There’s a pattern. Find that pattern and you’ve discovered a step.
An easy example: the complex change will mean that all subclasses of X must now implement a method differently than they did before. When you boldly re-derive, you get blood in the gutters from the fact that none of those classes does it.
You just found a step, a bunch of them, in fact.
The meta-step: make all soon-to-be-X classes implement the new method. Individual steps, make class 1 implement new method, and so on.
You can press on for a while, usually, discovering these step dependencies. Make post-its of them.
If you’re a noob, the hardest thing in the world is throwing away the code you just typed. If you’re a pro, you do it every day. Do it.
Now you have some or all of the precursor steps on your post-its. You’ve empirically determined how to make your big change small. This backwards-working seems hard at first. But the thing that makes it hard is over-valuing the text you typed and undervaluing your mind.
I type fast. It’s the 21st century. All geeks type fast. As we’ve said over and again: typing is not the bottleneck.
The change I’m making today is huge. It will involve lots and lots of differences. The commit would be many hundreds of lines of code. But I did my thing of pushing the huge change for a while, noting the small changes it requires. And now I’ve got some of what I need.
Note that if a change is big enough, pushing it like this won’t get you all of what you need, only part. That’s okay. Since whatever steps I discover this way are green-to-green, I’m perfectly happy that they only take me part of the way. Once they’re in and committed, I’ll repeat, trying the now-smaller huge change again, and seeing what steps fall out of that effort.
Eventually, the huge change remainder will become a small change. And I make it, and we’re done.
Notice: because I am insisting on green-to-green steps, I really CAN DO NO WRONG.
Any green-to-green code change is "okay". It might not be right, it might not be best, it might not be needed. But it’s okay. When you’re still skill-building, your version of "huge" will be smaller than when you’re a master.
But the approach still works. Try it.