Skip to main content
 /  Around 6 minutes to read

The Cleanup Tax

You always pay for the shortcuts.

It just takes a week or two for the bill to show up. A recent project I worked on shipped with 231 bug tickets in the first week after launch. The timeline was aggressive, the scope shifted late, and everyone involved knew corners were being cut.

The Cleanup Tax

The deadline was the deadline, so we shipped and dealt with the fallout after.

That fallout was an extra week of triage, stress, and fixing things in production that should have been caught before anyone saw them.

The time we "saved" by rushing didn't save anything. It just relocated the work to the worst possible moment, when real users were watching and the client was refreshing their inbox waiting for updates.

I've been building things on the internet for over 20 years, and this pattern has played out enough times that I should be immune to it by now. But deadline pressure has a way of making smart people agree to things they know are going to hurt later.

Borrowed Time

Ward Cunningham coined the term "technical debt" in the early 90s to explain to his financial colleagues why code sometimes needs to be rewritten. The metaphor has held up remarkably well because it captures the exact mechanics of what happens when you cut corners during development.

You're borrowing time from the future, and future-you always gets stuck with a worse version of the work.

Every shortcut you skip during building shows up later as a bug ticket, a support email, or a moment where a user loses trust in your product.

And fixing things in production is always harder, slower, and more stressful than fixing them during development because you're debugging under pressure with real users watching, which is the worst possible environment for careful work.

Those 231 tickets took a full week to clear.

That's roughly the same amount of time that proper QA and polish would have taken before launch, except the pre-launch version of that week would have been calm, methodical, and private. Instead we got a week of firefighting with a live audience.

Research on technical debt consistently shows that shortcuts made under deadline pressure generate disproportionate future costs. A retrospective study published through ACM found that documentation debt alone added roughly 47% extra maintenance effort on top of the original development cost. The shortcuts feel small in the moment, but the invoices that follow are anything but.

The Speed Religion

The indie builder world has spent years optimizing for speed. Ship fast, iterate, get feedback, move quickly.

And there's real wisdom in that advice, especially compared to the alternative of perfecting something in isolation for months while the market moves without you.

But the pendulum has swung too far.

AI tools have made it possible to generate entire features in an afternoon, and the "I built this in a weekend" posts have created an expectation that speed is the primary measure of builder competence.

The cultural pressure to ship fast has become so strong that taking your time feels like weakness, and admitting you need another week of polish feels like confessing to some kind of failure.

The result is a growing pile of software that technically functions but feels unfinished at every edge...

Buttons that work but feel sluggish, forms that submit but give no feedback about what just happened, and flows that make sense to the builder who spent three months staring at the codebase but confuse every actual user within seconds of arriving.

The Taste Gap

There's a quality that well-made software has that's hard to name but immediately obvious when you use it.

Things like loading states that tell you something is happening instead of leaving you wondering whether the button did anything, or the error message that actually explains what went wrong instead of showing you a stack trace, or the animation that's just fast enough to feel responsive without being slow enough to notice.

These details don't show up in feature lists and they rarely get prioritized in sprint planning, but they're the difference between software people tolerate and software people trust enough to pay for.

AI can generate code that passes tests, but taste is still a human skill that requires attention and time.

You can't vibe code your way to polish. Not yet at least.

The small decisions about spacing, timing, feedback, and copy are the things that make a product feel like someone actually cared, and they require the kind of slow, deliberate attention that speed culture actively discourages.

I think about this every time I use a product where the happy path works fine but the first unexpected state reveals that nobody thought about what happens when things go sideways.

Empty states with no guidance, error handling that swallows the problem and shows nothing, confirmation flows that leave you unsure whether the action went through.

These are all taste gaps rather than feature gaps, and they erode trust faster than any missing feature ever could.

Vibe Coding Hangover

This is going to catch up with the industry. People are shipping AI-generated features at unprecedented speed, and the technical debt is piling up just as fast.

The code works, mostly, but the people shipping it often don't fully understand what it's doing, which means when it breaks they can't diagnose the problem quickly because they have to reverse-engineer their own product before they can fix it.

More than half of companies already dedicate at least a quarter of their annual budget to technical debt, and that number was established before the current wave of AI-generated code.

We're going to see a significant amount of time spent cleaning up code that was shipped fast and understood slowly.

You've probably already encountered this in products you use.

Like the app that clearly had AI write the error messages because they're technically correct but completely unhelpful, or the feature that works perfectly in the demo but falls apart with real data, or the onboarding flow that was clearly never tested by a human who hadn't already seen the product fifteen times during development.

The speed is seductive.

I use AI tools every day and they're genuinely incredible at accelerating the building process. But acceleration without understanding creates a specific kind of fragility where everything works until it doesn't, and when it doesn't, nobody knows why.

What "Finished" Actually Means

A product is finished when a real person can use it without hitting something that makes them lose confidence.

That bar has nothing to do with feature count and everything to do with the hundreds of small things that sit between "it works on my machine" and "I'd give this my credit card."

Here's what finished actually looks like in practice:

Area What "Shipped" Looks Like What "Finished" Looks Like
Error handling Generic error message or silent failure Specific, helpful message that tells the user what happened and what to do next
Loading states Nothing visible while data loads Clear indicator that something is happening, preventing double-clicks and confusion
Empty Blank screen with no context Guidance on what to do next and why the screen is empty
Form validation Errors shown after submission Inline validation that catches mistakes before the user hits submit
Mobile experience Desktop layout squeezed into a small screen Layouts and interactions designed for how people actually use their phones
Edge cases Crashes or weird behavior on unexpected input Graceful handling that keeps the user oriented and in control

None of these will make your launch tweet go viral, and none of them will impress the people scrolling through your Product Hunt page. But they're the reason people come back after the first visit, and they're the reason people trust you enough to enter their credit card.

When Cutting Corners Is the Right Call

I'd be dishonest if I said you should never cut corners. Sometimes the deadline is real and the tradeoff is legitimate, whether that's client work with hard dates that don't move, product launches with competitive windows that close, or seasonal opportunities that expire.

Cutting corners occasionally when the situation demands it is fine. The problem is when it becomes your default mode, when speed becomes your identity rather than a tactical decision you make deliberately.

The difference between a builder who ships fast with intention and one who ships fast out of habit is that the first one knows exactly what they skipped and has a plan to go back and fix it. The second one doesn't realize anything was skipped until the tickets start rolling in.

I’ve been both of these builders at different points, and the 231-ticket version is not the one I want to keep being.

A practical approach that's worked for me is keeping a "skipped" list during development.

Every time I consciously decide to cut a corner because of time pressure, I write it down. The shortcut still happens, but it's documented rather than forgotten, which means the cleanup is planned rather than reactive.

That Invoice Always Arrives

Those 231 bug tickets represented known risks that we accepted because the deadline took priority over the polish.

Every single one of them was something that someone on the team knew should have been handled before launch.

And the cleanup costs more than doing the work properly would have. It always does, because fixing things in production adds the overhead of user-facing pressure, context switching between triage and regular work, and the reputational cost of users hitting problems that should have been caught.

The next time you're weighing whether to skip the QA pass, cut the polish, or ship something you know isn't quite ready, remember that you're not saving time.

Instead you're deciding when and where you'd rather spend it, and production is always the most expensive place to learn what you should have caught in development.