Founding as a Developer — Validate Before You Build
Technical Debt vs. Shipping Speed — Measure the Interest, Decide When to Pay
In one line
Technical debt is not a bad thing but a loan that carries interest. An early product borrows on purpose to learn fast. The problem is not measuring the interest. If you measure the interest (time that leaks outside the plan) and deployment stability from deployment records and work logs, and put the cost of paying it off, the payback period, and the value of the features that get postponed on one line, "should we pay it off now" becomes a calculation rather than an opinion.
Why this was needed
A small team is torn between two voices. "If we don't fix it now we'll never fix it" and "we survive only by shipping the features customers want first". Both are right, so the meeting never ends. The conclusion is usually decided by whichever side is louder.
In his technical debt article, Martin Fowler writes that Ward Cunningham coined this metaphor in a 1992 OOPSLA experience report, and he explains the extra effort required every time you add a feature because of a flaw in the code as the interest, and the effort of clearing that flaw as the principal. You can use that framework as it is. If the interest is large and growing and the principal is small, paying it off is faster, and if the interest is small, it is better to spend that time shipping features.
How it works
Deployment stability — the DORA metrics. The metrics guide on dora.dev lists change lead time (the time from a change committed to version control until it is deployed to production), deployment frequency, and failed deployment recovery time as throughput metrics, and change fail rate (the share of deployments that needed immediate intervention right after deployment) and deployment rework rate (the share of unplanned deployments made because of production incidents) as instability metrics. A module with accumulated debt commonly has infrequent deployments, frequent failures, long recoveries, and many incident-response deployments.
Median over mean. Lead time has a few changes that sat for days mixed in. The mean is pulled by those few and hides how long a typical change takes. This lab has you write the median and mean side by side to see the difference.
Measuring interest. The "unplanned work hours" recorded per module each week (bug and outage response) are the interest. Do not look only at the mean; look at the trend — if, comparing the first 4 weeks with the last 4 weeks, it is growing, the basis for the decision to pay it off must be not the past average but the recent interest.
Deciding whether to pay it off. This lab calculates in the following order (all values and rules are examples).
| Value | Calculation |
|---|---|
| Savings (hours/week) | Recent interest × the share the refactoring reduces |
| Payback period (weeks) | Refactoring cost (hours) ÷ savings |
| Net savings over the horizon (won) | (savings × horizon − cost) × hourly cost |
| Cost of delay (won) | (cost ÷ team weekly capacity) × the feature's weekly value |
If the team cannot build features while refactoring, the features are delayed by that much and the value those features would have earned each week is lost — this is the cost of delay. If the net savings over the horizon of the candidate with the shortest payback period is greater than the cost of delay, pay it off first; otherwise ship the feature first. An estimate such as "the refactoring cuts interest by 70%" can be wrong, so writing the estimate down and comparing it with the actual interest after paying it off is what completes the loop.
Where to record the debt. To measure interest, you must record unplanned work by module. You do not need grand tooling — leaving only an "unplanned" marker, the module name, and the hours spent in the issue tracker gives you weekly totals. Without records, interest exists only as a feeling that "everyone is busy", and a feeling cannot beat the numbers of feature requests.
You do not need to pay off all debt. Experimental code that will soon be thrown away, and the debt in a module that rarely changes, has interest close to 0. As Fowler said, interest attaches when you change that code. So choose candidates to pay off not from "ugly code" but from "code that changes often and creates unplanned work". A module where both change frequency and unplanned work are high is the first candidate.
What it looks like in the field
- Every time you touch only the payment module, deployment fails, recovery takes half a day, and every Friday ends in outage response. The interest is not recorded, so nobody knows its size.
- There is only the statement "refactoring will make it faster", with no numbers for how much or from when, so it gets pushed aside by features every time.
- Conversely, you postpone a release by a month fixing old code with almost no interest "because it's ugly to look at".
How to notice when you are wrong
- If the mean and median of lead time are very different, there is a long tail. Open the changes in that tail separately and look at the cause — was it waiting for review, or waiting for a deployment window?
- Check that the denominator of the change fail rate is the number of deployments. If you divide by the number of incidents or days, a team that deploys often is at a disadvantage.
- If you used a 12-week mean for the interest estimate, also look at the trend. If you judge growing interest by its mean, you miss the time to pay it off.
- A few weeks after the decision, measure the unplanned work again and compare it with the estimate. An estimate you did not compare will be wrong by the same amount in the next decision too.
What you will do in the next lab
From 12 weeks of deployment and work records, you calculate the DORA metrics per service and see why the median and mean of lead time differ. You measure interest by module and its trend, calculate the payback period, net savings, and cost of delay of two refactoring candidates, and decide by the rule. The grader also runs your functions against shaken records.