
Perfection is the Enemy of Progress
Your no-BS weekly brief on software engineering.
Join 100,000+ developers
Have you ever worked with a developer who insisted on designing a system as if deadlines didn’t exist? One who aimed to architect the perfect solution, addressing not just today’s needs but every conceivable future scenario? It’s an admirable mindset, but also one that can lead to paralysis.
As engineers, we love solving complex problems. But the real challenge isn’t in designing the most comprehensive system—it’s in distilling complexity into the simplest, most effective solution.
I didn't have time to write a short letter, so I wrote a long one instead.
Mark Twain
A developer might say: "I didn’t have time to write architecturally sound code, so I wrote some short-term hacks instead."
This quote captures a fundamental truth about engineering: simplicity is hard. It takes effort to strip a solution down to only what’s necessary while still leaving room for the unknown.
So Hacks are Good Now?
You might be left thinking that hacks are a part of life and we can keep moving forward. This is to some degree, in fact, true. Show me one production app that has zero shortcuts taken. I bet you could look in your codebase now and find a #TODO
that was written a long time ago.
The point isn't to avoid tech debt. The point is to leverage it...and then pay it off.
This inevitability of shortcuts is precisely why managing technical debt proactively is crucial—before temporary fixes become long-term obstacles.
How to Pay Down Technical Debt the Right Way
Now that we've established that hacks are inevitable and sometimes even necessary, the real question is: how do you pay down debt before it becomes a major problem?
Debt Should Have a Purpose
Shortcuts should serve a temporary purpose, not become permanent fixtures in your codebase. If a hack stays indefinitely, it stops being a tradeoff and turns into a liability.
Early in my consulting career, I worked with a startup that hardcoded pricing tiers to meet a fast launch deadline. Initially, this hack accelerated their iteration, but two years later, updating pricing required wading through scattered conditionals across multiple services. What began as a shortcut had morphed into a significant bottleneck—highlighting the need for an exit strategy from temporary hacks.
The key takeaway? Short-term hacks are fine—but only if you give yourself an escape plan.
Prioritize Based on Cost and Impact
Not all technical debt needs to be paid off immediately. The goal is to reduce friction where it matters most.
At another company, we faced a tough prioritization decision. Their authentication system was outdated and riddled with legacy quirks, but it worked. Meanwhile, their checkout process—one of the most business-critical parts of the application—was inefficient, bogged down by unnecessary API calls that slowed transactions for every single customer.
Instead of overhauling authentication just because it was messy, we focused on optimizing checkout. This change had an immediate impact, improving conversion rates and reducing infrastructure costs.
The lesson? Not all technical debt is equal. Paying down debt should focus on impact, not just aesthetics.
Recognizing “Expiration Dates” on Short-Term Hacks
Some hacks have a natural shelf life—for example, hardcoded values in an experiment that was meant to last only three months.
Consider a company I consulted for that had built a scrappy email notification system to handle one-off customer requests. At first, this was a clever hack—it allowed them to respond quickly without over-engineering a solution.
But as their product matured, this makeshift system became a liability. Every new notification type required fragile, repetitive code, and eventually, new features were delayed because modifying the notification system had become too cumbersome. They had reached the expiration date on this particular piece of technical debt.
The takeaway? Hacks are useful—until they start slowing you down more than they speed you up.
Paying Down Debt Safely
Paying down technical debt safely means reducing risk while improving maintainability. Here are some effective strategies:
- Refactor Incrementally – Instead of overhauling an entire system at once, clean up problematic areas as part of ongoing feature work. Small, incremental improvements prevent disruption.
- Introduce Test Coverage – Before modifying legacy code, ensure you have sufficient tests to catch regressions. Automated tests provide confidence when making changes.
- Document Intentional Debt – Clearly mark shortcuts in the codebase with comments, tickets, or internal documentation, so future engineers know why a decision was made and when to revisit it.
- Use Feature Flags – When refactoring core functionality, deploy changes behind feature flags. This allows you to validate improvements gradually without risking the entire system.
- Measure Impact Before Fixing – Not all tech debt is urgent. Prioritize fixes based on how much they slow development, increase operational costs, or introduce risks.
- Leverage Strangler Pattern – Instead of rewriting legacy systems from scratch, build new components alongside the old ones and gradually phase out the outdated code.
- Timebox Tech Debt Cleanup – Allocate dedicated time in sprints for paying down debt. Without intentional effort, it often gets ignored in favor of new features.
Final Thoughts
Technical debt isn’t just a coding challenge—it’s a tradeoff problem. If fixing messy code unlocks real value for your team or product, invest in refactoring. If not, consider it a calculated risk.
Reality is choosing which debts are worth paying down and which ones you can let ride. It’s about balancing speed, maintainability, and business value without getting stuck in perfectionism.
So next time you're staring at messy code, ask yourself: Does fixing this unlock real value, or just satisfy my inner neat freak? If it makes your team faster, your product more reliable, or your future self less miserable—pay it down. If not, let it ride.
The best engineers don’t chase perfection. They make smart tradeoffs.