Trapped in the Purgatory of a Big Refactoring

Sometimes, it's not just a method that needs refactoring, or even a class. Sometimes it's several large packages with a spider web of dependents that just need a complete "rehacktoring." This can happen when years of legacy code build up in a system. It is complicated by the fact that the thing you want to change or delete or rename or move has tendrils of dependents spread all across the system, sometimes into classloaders and reflection and dynamic scripts that you cannot begin to search-and-replace all of. It is going to be a big, long slog into the swamp.

We don't want our massive change to be a surprise to our team, though. We want to commit and merge the bits as we're going along. They don't represent complete refactorings. We might have pulled out a class just to put some code in a separate place, knowing that down the road we're going to merge it together with some other class and move that other method somewhere else. We're not quite sure where it's all going, but we have to do it and hope no one tries to use that stuff before it gets to where it needs to be.

Refactorings are supposed to be small, targeted, and usable when they are finished, but sometimes massively entangled legacy code doesn't afford that luxury. We have to start tearing things apart somewhere, knowing that there's eventually a light at the end of the tunnel. The problem is that to those we work with, that light might look like an oncoming train.

Large refactorings are large. They may involve writing a mountain of new tests, breaking up odd dependencies in sometimes ugly ways, splitting of pieces that, out of a larger context, don't make a whole lot of sense. Large refactorings are exhausting. The person doing them (and usually it's only a person or two at a time) has a finite amount of time, energy, and mental capacity. There's only so much pretzel logic a person can look at in a day, week, or month before they become exhausted. There may also be a lot of moving parts. Because of the tangled web of dependencies, this refactoring here might need to take a break until that one over there is done.

To the people not doing the refactoring, this seems like a lot of wasted energy. Large legacy codebases are not going to change overnight. Sometimes the resistance goes deeper to a belief that there's nothing wrong with that legacy code. All of these little code changes don't really make that much of a different. On top of that, there are real features that need to get done and out the door. Trying to rewrite the whole system doesn't add any customer value.

Because of these competing forces, out big refactoring ends up in a purgatory of sorts, too far away from being finished and to tiring to keep doing. Because of all the half-done changes, the codebase can actual get worse. Maybe that light is an oncoming train?

How can we get these big refactorings out of code purgatory? Well, I can say that isn't a train (usually). Adding a good suite of tests will always benefit development, if nothing else good comes out. Big refactorings executed successfully, though, can be almost magical at the end, radically transforming not just the codebase, but the entire way that the code is written from then on. Features can be added more quickly and more cleanly. Separating concerns means that parts can be reused in ways that were unimaginable before. The code can be leaner, cleaner, and more efficient.

The way out is to keep going, but at a measured pace. Though refactoring can feel great, adding new features and improving the value of the software is equally important. It is not more important because investing in code quality has a value itself. It is not less important because without creating customer value, the software can't generate enough revenue to sustain itself. There must be a reasonable balance between the two. The dividends of a big refactoring are not paid immediately, but they are significant when they come. The person doing the refactoring needs to keep motivated and passionate. That may mean taking breaks from the refactoring on occasion so to not burn out on it. The people not doing the refactoring need to give understanding and support that this will help the code when done correctly. They may need to see a roadmap to understand where it's all going, but they also need to understand that part of refactoring is discovering the path as we go.

The promised land of big refactorings is real, even if we have to wander in the desert a while first.


Popular posts from this blog

The Timeline of Errors

Magic Numbers, Semantics, and Compiler Errors

The Cone of Code Uncertainty