Posted by: Ben Rubenstein
code, database, development
Maintenance image via Shutterstock
By Steve Poling (@stevepoling)
“The code is a steaming pile and we’ve got to rewrite it.”
Perhaps you’ve heard this and felt inclined to agree. But before you roll up your sleeves to do a comprehensive rewrite, let’s pause for a moment to ask a question: “Why is the code in this suboptimal state?”
The reasons are many. The original implementers may have been incompetent. Or incompetent bosses did not invest the time to make it right the first time. It is tempting to identify one actor in the history of a software project and make him the scapegoat. But scapegoating can obscure your vision of where the true problem lies, because there may be no scapegoat.
Maybe the badness of the code is the natural result of fixing bugs in the original implementation. People of good faith and adequate skills can approach a codebase with a bug report in hand then make the code work while making the codebase just a little bit worse.
Most times an original design won’t consider the vagaries of reality that come along later as bug reports. The fix often does not fit into the original scheme of the codebase and it gets bolted on like some aftermarket car parts you’ll find in the J. C. Whitney catalog. And because it didn’t fit into the original scheme, it may introduce additional bugs causing additional fixes to get bolted onto the earlier ones. The end result can be a codebase that seems like something from a Mad Max movie.
Don’t make a scapegoat of the guy doing the maintenance. He’s just doing a bug fix with no desire to refactor the existing design. If he refactors the existing design he risks breaking something that’s working. Just get in, fix the bug, get out. If he’s smart, he writes unit test(s) that recreates the conditions of the bug report and verifies the fix did indeed hold.
This accumulation of cruft in a codebase exhibits debt-like behavior. Every bug fix takes longer because the programmer has to sort through extraneous code to get to the problem. When this overhead gets too large, it’s easy to throw up one’s hands and demand a rewrite. I think this is wrong.
Why not continuously refactor the codebase? Probably because the codebase doesn’t have adequate unit test coverage. Or it has stupid codebase coverage. Stupid codebase coverage means writing unit tests that just exercise code without any real insight into the intent of the code being tested. This usually happens after the code has been written and someone demands 100% unit test coverage. It’s better than nothing I suppose.
Let’s suppose for sake of argument that a codebase has adequate unit test coverage (here I’ll conflate unit tests with functional tests, acceptance tests, and any other tests of anything else I care about). These tests allow the programmer to refactor without fear. His fix need not be encapsulated in its own island of sanity, but can fully integrate with the rest of the codebase that he can adjust to make that integration more graceful. If he sees cruft he can cut it out. If he cuts too deep there’s a unit test that has his back. The result is less technical debt and greater stability.
A codebase is a capital asset. It needs to be maintained like a building must be repainted or a vehicle’s oil changed. We often think of software maintenance as mere bug fixes and feature requests, but it extends to continuous refactoring and automated tests to instrument correctness.
Steve Poling was born, raised and lives in West Michigan with his wife and kids. He uses his training in Applied Mathematics and Computer Science as a C++/C# poet by day while writing Subversive Fiction by night. Steve has an abiding interest in philosophy and potato cannons. He writes SF, crime fiction, an occasional fractured fairy tale, and steampunk. His current writing project is a steampunk novel, Steamship to Kashmir - provided he isn’t distracted by something new & shiny.