Rebuilding After Launch: Technical Debt and Fresh Starts

After shipping under pressure, it's time to address the technical debt we accumulated - deciding what to fix, what to rewrite, and what to accept.

Evyatar Bluzer
3 min read

The fires from launch are mostly out, which means we finally have to face the pile of IOUs we wrote to ourselves during crunch.

The Debt Inventory

The debt comes in three flavors. There are expedient hacks, code that solves the immediate problem poorly: magic numbers tuned for specific hardware units, race conditions "fixed" with sleep statements, error handling that ignores errors. There is missing infrastructure, things we should have built but skipped - automated integration tests, performance regression tracking, comprehensive logging. And there are architecture mismatches, designs that never fit the requirements: synchronous APIs that should be async, components with circular dependencies, abstractions at the wrong level.

The Prioritization Framework

Not all debt is equal. We rank it on three axes. Pain: how much does it slow us down day to day - does it block new features, cause recurring bugs, force workarounds? Risk: what's the worst case if we leave it - customer-visible failures, security vulnerabilities, data corruption? Cost: how hard is the fix - is the code isolated or deeply integrated, is the scope clear or murky, does documentation exist or are we reverse engineering our own system?

What We're Tackling

Q4 priorities:

  1. Tracking system integration tests: We've had three regressions from changes in one component breaking another, the integration problem that ate last year's Q3-Q4. Need automated catch.

  2. Sensor driver rewrite: The depth sensor driver was written under time pressure (the July kind). It works but is fragile. Rewriting with proper error handling and documentation.

  3. Calibration data management: We have calibration parameters scattered across files, database, and firmware. Consolidating into single source of truth.

What We're Not Fixing

Some debt isn't worth paying. Stable bad code that works and never needs to change gets left alone. Code that V2 will make obsolete anyway - V2 will have different sensors - doesn't deserve polish now. And some of what looks like debt is really exploratory code where we're still learning; rewriting it now would be premature.

The Rewrite Temptation

Post-launch, there's always pressure to "do it right this time" - full rewrite, clean architecture, new tech stack. I'm pushing back. Rewrites take 2x as long as estimated, you lose the institutional knowledge encoded in the old code, and new code has new bugs. Incremental improvement wins: replace one component at a time, keep interfaces stable, run old and new in parallel during the transition.

Debt Prevention

Paying down debt matters less than not accumulating it in the first place. So we're changing how we work. A hack now comes with a time box ("this is okay for 2 weeks") and a calendar reminder. Every shortcut gets logged with a justification and a cleanup plan. PRs that add untracked debt don't get approved. And 20% of sprint capacity is reserved for debt reduction.

None of it is glamorous. It's how you keep your velocity over years.

Comments