Several years ago, I bought one of those Christmas trees with lights already strung up from a big box store. Every December, I go to the basement where it’s stored, dust it off, set it up in our living room, plug it in, and it lights up! Unfortunately, the pre-installed lights are incandescent instead of newer LEDs, and after this many years, most of the lights have now burned out. Last year, at least half the lights were still working, but this year three-quarters of my tree went dark, so I decided to do something about it. After multiple failed attempts to locate and replace individual bulbs (more on that later), I decided to just remove and replace the entire string of dead lights from the tree. While unraveling the tightly wound wires from the fake branches, I couldn’t help but notice how much this was like refactoring an old tangled code base of ours at work…
Here are 5 ways that fixing my old Christmas lights is like refactoring an equally old codebase:
1. So tightly embedded, it’s like someone really doesn’t want you to remove it…
These weren’t like the standalone string lights that I loosely hung around our tree as a kid. To be able to stay fixed on the tree through multiple holiday seasons, they really wrapped the wires around each branch tight, going towards the center of the tree, then doubling back. Just like code without clear boundaries, where logic cuts through multiple layers, leaking abstractions all over the place, it’s hard to tear it out without messing up something else. They don’t call it “spaghetti code” for nothing. Untangling this was/is a pain!
2. Modularity is appreciated
All the light bulbs on my tree can be individually removed from the little plastic bases on the wire and replaced. There seems to be a standard size bulb that fits most string lights that you can buy from any hardware store. I even found that LED bulbs use a different size base compared to incandescent ones to prevent mixing incompatible bulbs— how thoughtful! It’s always nice to have a well-thought out, standard interface for your components, so you can easily swap them out for a newer version.
Sadly, this was ultimately insufficient because…
3. Read the docs
I didn’t find this warning label until after I’d removed the lights.
Just because something fits an interface doesn’t mean it’s fully compatible. Imagine my surprise when each new bulb I installed burned out the instant I turned it on with my existing lights. After this happened twice in a row, I figured it wasn’t random chance. Turns out somewhere deep in my tree, there was a sticker on the wire warning “ONLY USE 2.5 VOLT, 170mA LAMPS.” The ones I bought? 6 Volt, 80 mA. Oops.
Reminds me of that time we replaced Guava’s Base64 library with Java’s Base64 library in our app server and suddenly some customers couldn’t login. Both libraries had the exact same interface, but there was a subtle difference in how they handled whitespace in the input — Guava’s library would ignore it, while Java’s would throw an IllegalArgumentException. Turns out customer provided data (in this case a Base64-encoded SAML certificate) doesn’t always perfectly follow the specs. Who knew? That’s why they teach us to test the edge cases…
4. It’s going to get worse before it gets better
Worse. Definitely worse.
Midway through removing the string of lights from my tree, my arms were getting tired, and a tangled mess of wires was hanging off to one side. It was ugly, but a necessary step towards getting the job done. When refactoring an old codebase, sometimes you have to start by duplicating or inlining code that was spread out so you can see where it really belongs. Like my tangled bundle of wires, your classes get bigger at first, but doing that lets you later subdivide and organize the code into the way it should be.
5. When all else fails, replace the whole thing
Refactoring a mess is a noble thing to do, but sometimes you need to recognize when the project is a lost cause. Instead of trying to locate and replace burnt out bulbs, I decided replacing the whole string was going to be way easier. Plus, I could upgrade to the latest, most power efficient version of LED lighting. Ultimately, that’s the same goal as refactoring — to keep your application up-to-date and running smoothly too!