The Universal Cringe of Looking at Old Code
Almost every developer, regardless of experience level, has had the experience of opening code they wrote months or years earlier and immediately wincing at it — clumsy solutions to problems that now seem obvious, structure that feels needlessly convoluted, naming choices that no longer make sense even to the person who originally chose them. This reaction is so common it’s become something of a running joke within the programming community, but it also reflects something genuinely meaningful about how the skill develops over time.
This isn’t really a sign that the old code was unusually bad, or that the developer was unusually inexperienced at the time. It’s simply evidence of genuine skill growth — the specific things you notice as flaws in old code are usually things you didn’t have the knowledge or experience to recognize as problems when you originally wrote it, which is exactly why growth in this field so often comes paired with this particular kind of retrospective discomfort.
The urge to immediately rewrite everything from scratch the moment this discomfort sets in, however, isn’t always the right response, even though it’s an extremely common one. Understanding when a rewrite is genuinely worthwhile versus when it’s mostly driven by this natural but sometimes misleading discomfort is a skill in its own right, separate from the technical skill of actually writing better code.
When a Rewrite Actually Makes Sense
A rewrite tends to be genuinely justified when the existing code’s structural problems are actively slowing down current work — when adding a reasonably simple new feature requires touching an unreasonable number of different places in the codebase, or when bugs keep resurfacing in the same fragile area because the underlying structure makes it genuinely difficult to fix things properly rather than just patching symptoms repeatedly.
It’s also often justified when the original code was built on assumptions that have since changed significantly — a system originally designed for a small scale that now needs to handle vastly more data or users than originally anticipated, for instance, where incremental patches can only stretch the original architecture so far before a more fundamental restructuring genuinely becomes the more efficient path forward.
On the other hand, code that works reliably, is reasonably maintainable even if not aesthetically pleasing by current standards, and isn’t actively causing ongoing problems is often better left alone, even if it triggers that familiar cringe reaction. The old, sometimes-mocked engineering wisdom ‘if it isn’t broken, don’t fix it’ holds up reasonably well here, since a rewrite driven purely by aesthetic discomfort risks introducing brand-new bugs into a system that was, in practical terms, actually working just fine.
A Healthier Way to Think About This Instinct
Rather than treating the urge to rewrite as an automatic signal to act on immediately, it’s worth treating it as useful information about your own growth as a developer — a marker worth noting, even journaling briefly, without necessarily requiring immediate action on every old piece of code that triggers the reaction.
Incremental refactoring, improving specific problematic sections of code gradually over time rather than committing to one large, risky rewrite of an entire system, often captures most of the genuine benefit with considerably less risk than a full rewrite carries. This approach lets you apply newer, better skills to the code that’s actually still actively causing friction, without the substantial risk of a large-scale rewrite introducing new problems into a system that mostly works.
Ultimately, this recurring cringe-and-rewrite-urge cycle is really just visible evidence of a healthy learning trajectory. Developers who stop feeling this way about their old code have typically stopped growing, not because their old code has finally become perfect, but because they’ve stopped developing the newer perspective that would have let them notice the flaws in the first place.
What This Cycle Teaches About Long-Term Skill Development
Looking at this pattern across an entire career rather than any single project reveals something genuinely useful about how programming skill actually develops over time — it’s rarely a smooth, linear improvement, but rather a series of distinct plateaus punctuated by these periodic moments of retrospective realization, each one representing a genuine, meaningful jump in understanding rather than simply gradual, incremental refinement.
Keeping some old code around deliberately, even code you’d genuinely never want to actually ship or use again, can serve as a surprisingly useful, concrete record of your own growth over time, offering tangible, specific evidence of how much your judgment and technical instincts have actually developed, in a way that’s considerably harder to appreciate in the moment without this kind of direct, retrospective comparison.
For newer developers specifically feeling discouraged by looking back at their own earlier work, it’s worth reframing that reaction entirely: the discomfort itself is genuine evidence of real growth, not evidence of past incompetence. Every experienced, skilled developer has gone through this exact same cycle repeatedly throughout their own career, and will very likely continue experiencing it well into the future, regarding code they’re currently writing with complete confidence today.
That discomfort, uncomfortable as it feels in the moment, is genuinely one of the more reliable signs that your skills are continuing to grow in the right direction.
It’s also worth sharing this pattern openly with newer developers you might mentor, since seeing a senior, experienced colleague admit to the same cringe-and-improve cycle can be genuinely reassuring for someone early in their own career who assumes this discomfort is unique to their own inexperience. Normalizing this shared experience openly tends to make the entire learning process feel considerably less isolating for everyone involved.