culture
How to talk about debt with people who don't read code
The debt metaphor stopped working when it became a synonym for code we dislike. Debt as lead time and blocked features, repair budgets without a turf war, and what to say in planning.
By Andrei Gaspar · Editor, Tech Debt Weekly
The debt metaphor was invented for people who do not read code. Ward Cunningham reached for it in 1992 to explain to the finance-industry people paying for his software why shipping a quick version now and revising it later was a reasonable trade, and it worked because the audience understood loans. More than thirty years later the metaphor mostly does not work, and the reason is not that product leads stopped understanding loans.
It is that engineers stopped quoting an interest rate. "We have a lot of technical debt" is a request for time with no deliverable, no price, and no term. Every product lead has by now sat through at least one cleanup sprint that delivered exactly what it promised, which was nothing anyone could see. The word has become a synonym for code the current team dislikes, and it gets heard that way.
This piece is about the translation back: debt into product language, repair work into a budget that does not become a turf line, metrics that survive becoming visible, and the planning-meeting conversation itself, including what not to promise.
Why the metaphor stopped working
It got overloaded. Debt now covers a deliberate shortcut taken under deadline, a framework that aged out from under the team, a design that was right for the product three years ago, and code the newest engineer would have written differently. Those have completely different costs and completely different fixes, and one word for all four means the word carries no information.
It lost its numbers. A loan has a principal, a rate, and a term. Almost nobody says "this shortcut costs us twelve hours a week and would take six weeks to repay." Without the rate, debt is an adjective, and a product lead is being asked to allocate capacity on the strength of an adjective, from people who have an obvious interest in the answer.
And it became a morality play. Debt implies a borrower, and the borrower is the previous team, who are sometimes the people in the room, and sometimes the product lead who set the deadline. A conversation that opens with "we are drowning in debt" has already assigned blame before anyone has asked what the debt costs, and people who have been blamed do not fund the people blaming them.
None of this means abandoning the word. It means never using it without a number and a product noun attached.
Translating debt into product language
A product lead runs on three quantities they already track: how long things take, what breaks, and what is on the roadmap. Every piece of debt worth talking about maps onto at least one.
Lead time. "Changes in checkout take nine days from pull request to production. In the rest of the product they take two. The difference is the payment adapter." The DORA research made lead time for changes one of the four delivery metrics that engineering leadership already reports on. That sentence uses a number the product lead has seen before and does not need to be taught. Debt expressed as lead time is debt expressed as a delay on their roadmap.
Incident exposure. "The same subsystem started four of last quarter's incidents. Twenty-six engineer-hours, two of them customer-visible, one of them during the launch." Exposure, not blame: the roadmap runs through a part of the system that keeps failing, and the next launch runs through it too.
The feature you cannot build. "You asked for per-region pricing. It is a three-week feature on a clean tax module and a two-quarter feature on this one." This is the translation that lands hardest, because it attaches the debt to something the product lead already wants. The repair stops being an engineering line item and becomes the first phase of their feature.
| Engineering says | Product hears | Say instead |
|---|---|---|
| "The code is a mess" | "They do not like it" | "Changes here take four times as long as elsewhere" |
| "We have a lot of debt" | "An open-ended request for time" | "This module costs about 0.6 of an engineer a week" |
| "We need a cleanup sprint" | "Two weeks with nothing to show" | "Six weeks buys back that 0.6, and per-region pricing becomes a three-week feature" |
| "We can't do anything until we fix this" | "A threat" | "We can do it now at two quarters or after the fix at three weeks" |
| "The last team cut corners" | "Blame" | Nothing. Drop the sentence. |
The rule that generalizes the table: never present debt without a product noun. If you cannot name the feature it slows, the incident it caused, or the lead time it inflates, you do not yet have a case; you have a preference, and it should go on the write-off list until the ledger says otherwise.
Three ways to budget repair work
The turf war over repair time has three standard settlements, and each fails in a characteristic way.
A fixed budget, most often twenty percent of capacity. It is predictable and easy to defend, and it is the first thing cut in a crunch. Its worse failure is subtler: the percentage becomes a fence. Product treats it as the ceiling for all repair, engineering treats it as an entitlement. The twenty percent gets spent on whatever is most annoying rather than what is most expensive, because nobody inside the fence has to justify the choice to anyone outside it.
Attaching repair to feature work. The repair is scoped into the feature that needs it: the tax module gets cleaned up as phase one of per-region pricing. This is the easiest to sell, because it arrives with a deliverable, and it has the healthy effect that repair goes where the roadmap goes. It fails in two ways. The highest-interest debt in an area the roadmap is not touching this year never gets paid. And padding features with repair makes every feature look expensive, which trains product to ask for smaller features and trains engineers to hide the repair inside estimates, at which point nobody can see it at all.
Forcing functions. A runtime end-of-life, a compliance deadline, a launch that cannot ship on the old path. These are the most effective budgets there are, because the work is not optional and nobody has to argue for it. They are also the least controllable, and the temptation to manufacture them, to declare a deadline that is really a preference, is the fastest way to lose the trust the real ones earn.
The settlement that holds is all three drawing on one list. A small fixed floor, a few percent, funds the ratchets and the tooling: the lint rules, the codemods, the deprecation counts that keep debt from growing while nobody is looking. The large repairs attach to the features that need them and are argued for in the feature's own terms. Real forcing functions get their own dates. And every one of those draws from the same ranked ledger, with weekly interest and payback on every row, so that the argument in the room is about which item, not about what percentage. Percentages are turf. Items are decisions.
Sponsored:
The quarter a metric becomes a target
Goodhart's law, in Marilyn Strathern's phrasing, is that when a measure becomes a target it ceases to be a good measure. Engineering organizations rediscover this roughly one quarter after any code-health number appears on a dashboard someone is judged by.
Coverage targets produce tests that execute code and assert nothing. Complexity scores produce functions shredded into fragments too small to have a name. A "debt hours" figure from a static analysis tool gets re-baselined, or the rules that feed it get tuned, until the trend line goes the right way. Ticket counts in the debt backlog fall because tickets get closed as won't-fix. Lines-of-code-deleted rewards churn. In each case the number improved and the thing it was meant to stand for did not, and the organization is now paying to maintain a metric that lies.
The distortion is a reason to measure outcomes instead of code. Lead time for changes in the area, incident count and hours by subsystem, time to a new hire's first productive change, the number of remaining callers of a deprecated interface: these are hard to game because gaming them means doing the work. You can only make the deprecated-caller count go down by migrating callers. You can only make lead time in checkout drop by making checkout easier to change. Measure the interest, not the code, and the metric stays honest for as long as it stays an outcome.
Two norms keep it that way. A code-health number is never tied to an individual's or a team's performance goal; it is published as information, the way an incident count is. And it is reviewed quarterly by people looking at it rather than optimized continuously by people paid on it.
The norms that create debt and the ones that retire it
Most debt is not a decision. It is the residue of everyday norms, which means the norms are where it gets created and where it can be retired.
Review. The most common origin of debt is a review comment that says "fine for now, we will fix it later" with no ticket, no owner, and no date. That is a loan with no note. The norm worth having is that a knowing shortcut merges with a named owner and a date, or with an explicit decision to write it off, and never with a bare "later." The opposite failure is also real: reviews that block on style and preference create the debt of the change that never got made, and the engineer who stops proposing improvements because each one costs a week of argument.
Ownership. Code without an owner accrues interest with nobody watching the rate. Every directory has an owning team, and when a team dissolves its code is reassigned that week, not eventually, because eventually is when the incident happens. Ownership is also what makes the ledger possible: someone has to be able to answer "how much longer did that take than it should have" about a specific area, and that someone is the owner.
On-call. The team that carries the pager for a system is the team with the incentive to fix it. Separate the pager from ownership, hand it to a platform or operations rotation, and you have separated the pain from the power to fix it, which is the most reliable debt-generating arrangement there is. Where the pager stays with the owners, post-incident action items become the most dependable source of funded repair work an organization has, provided the incident reviews are the blameless kind John Allspaw has argued for. A review that assigns blame produces defensive action items rather than useful ones.
Definition of done. Whether a migration finishes is decided by what the team means by done. If done is "the new path works," the old path stays forever. If done is "the old path is deleted and the lint rule that forbade it is removed," it does not. Write it down.
The planning meeting
The product lead on the other side of the table has commitments to sales, a roadmap they have already shown to their own leadership, and a history of engineering asks that consumed a quarter and produced nothing visible. They are entitled to ask, of any repair proposal: what does it cost, what do we get, when do we get it, what happens if we do not, and how will we know it worked. Bring answers to all five or do not bring the proposal.
What to bring is the ledger, cut down to three items. Each one has a product noun, a weekly cost in engineer-fractions, a price in engineer-weeks, a payback period, and an honest statement of what stays broken afterward. Bring two explicit write-offs as well, items you measured and are not asking for, because they are the evidence that you are ranking by cost and not by taste.
What to say, for each item, fits in three sentences. "The tax module costs us about twenty-four hours a week, six-tenths of an engineer, and it is the reason per-region pricing is a two-quarter feature. Six engineer-weeks buys most of that back and makes pricing a three-week feature. I want it scheduled ahead of the pricing work, not instead of it." Cost, consequence, price, and where it goes on their roadmap, in their units.
What not to say: that the code is a mess; that you need a cleanup sprint; that nothing can ship until this is fixed; anything about the team that wrote it. Each of those sentences has been said in that room before, by someone who then delivered nothing measurable, and each one costs you the credibility the ledger just earned.
What not to promise: that the interest goes to zero, because it will not; that velocity doubles, because you cannot measure that and they know it; a date for the whole codebase; that there will be no new debt afterward. Promise the measurement instead. "We will re-measure lead time in the tax module eight weeks after this lands and bring you the number, whatever it is." That is a promise you can keep, and keeping it is what makes the next ask cheap.
When the answer is no, take it. Write down the weekly interest you are carrying and the date of the decision, and bring the same item back next quarter with the updated figure. A no against a ledger entry is expensive in a way a no against an adjective never is, and it gets more expensive every quarter it stands. That is not a fight. It is a running tab, which is what the metaphor was supposed to mean all along.
Monday
Take the one piece of debt your team argues about most and write it down in the three translations: the lead time it inflates, the incidents it started, the feature it is blocking, by name. If you cannot fill in any of the three, move it to the write-off list and pick the next one.
Then look at your last ten merged pull requests for the phrase "fix later" and count how many have an owner and a date. That count is your team's rate of borrowing, and it is the first norm to change, because it costs nothing and it is the one the product lead will never see.
Comments
Loading comments…