Every developer has spent time working on at least one project that was rife with poorly or bizarrely-named variables/methods/types, dead code, impossibly long code blocks, misleading comments, contorted logic, ancient libraries and dependencies that are never upgraded, and worse.
“Someday,” of course, “we’ll clean that up” — but there are urgent features already promised to customers, urgent bugs, and of course everything is always running late because the codebase is so darn hard to work with.
So yeah, curse the earlier developers who made the first mistakes, right?
Well, the first implementation of anything is half proof-of-concept and usually rushed, and no one ever knows at the beginning of the project how to design for its entire lifespan. And the later developers needed to get these features added ASAP, these bugs fixed ..and after a while, trying to clean things up is an act of recklessness. Everyone is leery of changing code they don’t understand, so they tiptoe around adding in redundant code, touching only what they must, and not even updating comments (what are you going to write? “this does a bunch of weird stuff but at least line 2038 no longer crashes on nulls”?).
Methods sprawl into hundreds or thousands of lines (and have less & less connection to their original names).
Logic gets stranger (because it’s safer not to touch what’s already there… just sort of sneak in the new bit however you can).
Spaghetti code snowballs. (insert horrifying sound-effect here)
Notice that this doesn’t require incompetent developers at any point. If they aren’t somehow getting time to actively maintain the quality of the codebase, it will go straight to hell all by itself. It’s a natural process.
Let’s get to a more interesting insight I had into this whole mess, though. It’s a hell of a lot easier to fix a problem if you can explain it quickly without resorting to technical lingo.