Skip to main content

Why Tech Debt Estimates Are Always Wrong

Last updated . Sources are named and dated inline - how we source claims.

Everyone tells you to multiply the rewrite estimate by two or three. Almost nobody tells you why the original number was wrong, which is the only thing that would let you produce a better one.

Estimation error on debt work is not carelessness and it is not a discipline problem. It is a predictable consequence of how humans forecast unique-feeling tasks, and it has a well-studied name and a well-studied correction. This page covers both, plus the organizational behavior that makes the error worse every time you punish it.

Debt Work Is Harder to Estimate Than Feature Work

A feature has a specification. You may not know exactly how long it takes, but you know what "done" looks like before you start, and the surface area is bounded by the thing you agreed to build.

Debt work inverts that. The job is to find out what is actually in there. You are estimating the cost of removing something whose shape you cannot see until you start removing it, and the discoveries are not edge cases around the work -- the discoveries are the work. The undocumented consumer of the API you were going to delete. The batch job that depends on the column ordering. The behavior that looks like a bug and turns out to be a customer contract.

Feature estimation asks "how long will it take to build what I described?" Debt estimation asks "how long will it take to find out what I do not know?" The second question has no answer of the same kind, and pretending otherwise is where the error starts.

The Planning Fallacy and the Inside View

The underlying mechanism was described by Daniel Kahneman and Dan Lovallo in Management Science. Their abstract states it directly: "Decision makers have a strong tendency to consider problems as unique. They isolate the current choice from future opportunities and neglect the statistics of the past in evaluating current plans." The consequence follows in the next line: "Overly optimistic forecasts result from the adoption of an inside view of the problem, which anchors predictions on plans and scenarios."

That is exactly what a team does at a whiteboard. It builds a scenario -- extract this module, swap that adapter, migrate the callers, delete the old path -- and adds up the steps. The scenario is coherent, the arithmetic is correct, and the estimate is still far too low, because the scenario contains only the steps you can currently imagine. Every unimagined step is missing from the total, and unimagined steps are precisely what debt work consists of.

The Inside View

Look at this task, decompose it, sum the parts. It feels rigorous because it is detailed, and detail is what makes it persuasive to everyone in the room. It systematically excludes whatever nobody thought of, and it treats this project as unique -- which is what licenses ignoring every similar project that came before.

The Outside View

Ignore the details. Ask what happened the last several times this team did something in this category. That distribution already includes the surprises, because surprises happened in those projects too -- you simply do not have to predict which ones you will get this time.

Reference Class Forecasting

The outside view has an operational form. Bent Flyvbjerg's paper in the Project Management Journal presents it as "a promising new method called 'reference class forecasting'" built on the decision theory that won the 2002 Nobel prize in economics, and describes it as achieving "accuracy by basing forecasts on actual performance in a reference class of comparable projects." It was developed for infrastructure megaprojects, where optimistic forecasting is measured in billions rather than sprints, and it transfers to engineering work without modification.

The method is deliberately unglamorous. Identify a class of past work comparable to what you are about to do. Look at what that class actually cost, not what it was estimated to cost. Adjust your forecast toward that distribution. The hard part is not the arithmetic; it is admitting that your specific, carefully reasoned plan is weaker evidence than a boring list of what happened before.

Build the Class From Your Own History

You do not need an industry database. Your ticket tracker already holds every migration, extraction, and dependency upgrade this team has finished. Pull the last eight or ten pieces of comparable debt work and record what each one actually took, including the weeks nobody logged because the ticket sat in review.

Classify by Shape, Not by Subject

The useful reference class is not "payments work" but "replacing a component with many unknown callers" or "upgrading a framework across a major version." Shape predicts cost far better than subject matter, and it gives you a bigger sample to reason from.

Anchor on the Class, Then Adjust

Start from the class distribution and move toward your bottom-up estimate only for reasons you can name -- better test coverage here, a smaller blast radius there. "This time feels different" is not a reason. It is the inside view asking to be let back in.

"It Is Just a Small Refactor" Is the Most Expensive Sentence in Engineering

The word doing the damage is "just." It signals that no investigation is required, and it therefore prevents the investigation that would have revealed the actual size. The sentence is usually spoken honestly, by someone who has read the code and not the callers.

It is expensive for a second reason. A small estimate gets approved casually, without a checkpoint, a stakeholder, or a scope agreement. So when the work turns out to be four times larger, there is no mechanism to catch it -- the team is three weeks in, the sunk cost argument is loaded and ready, and nobody has the standing to stop it. Large estimates get scrutiny, which is a form of protection. Small estimates get waved through, which is not.

Practical rule: if someone says "just," ask how many callers there are and whether anyone has looked. If the answer is no, the honest estimate is not a number yet -- it is a timeboxed investigation. See rewrite versus refactor for what happens when this reasoning is applied to an entire system instead of one module.

Discovery Is a Line Item, Not an Overhead

Most debt estimates are estimates of the change. Nobody prices the finding out, even though on legacy work the finding out is routinely the larger half: reading code nobody has touched in years, tracing callers, reproducing behavior, writing characterization tests to pin down what the thing currently does before you dare alter it.

Give discovery its own line. It makes the estimate legible to a stakeholder, because "two weeks to understand the blast radius, then an estimate for the change" is a sentence a non-engineer can evaluate. And it makes the eventual overrun attributable: you can see whether the change was harder than expected or whether the system was simply more tangled than anyone knew, and those two failures call for completely different corrections next time.

Map the Callers

Static analysis finds the compile-time references. Reflection, configuration, scheduled jobs, and other teams' repositories do not show up there, and each is a classic source of the discovery that doubles a refactor.

Pin the Behavior

Characterization tests are discovery expressed as code. Writing them is where you learn which of the current oddities are bugs and which are load-bearing, and that answer changes the size of everything downstream.

Find the Owners

Coordination is a real cost. Discovering that a change needs sign-off from three teams on different release cadences can dominate the engineering work by an order of magnitude.

Timeboxes and Spikes: The Honest Answer to Irreducible Uncertainty

Some uncertainty cannot be reasoned away before the work starts. When that is the case, an estimate is a guess wearing a number, and the honest response is to stop estimating and start buying information.

A spike is a fixed purchase of learning: three days to establish whether the extraction is feasible and what it would touch, with a written finding at the end. A timebox is a fixed purchase of attempt: two weeks on this, then we stop and decide regardless of state. Both convert an open-ended risk into a known, capped cost, which is the thing a stakeholder actually wanted from the estimate in the first place.

Make the Exit Criteria Explicit

A timebox with no decision at the end is just an untracked project. Write down in advance what you will know, who decides, and what the options are: proceed with a real estimate, descope, or abandon. Abandoning after a spike is a success, not a failure -- you bought the information cheaply and it said no.

Keep Them Genuinely Fixed

A timebox that is extended twice is not a timebox, and once a team has seen that happen the mechanism stops working -- it becomes another estimate to be missed. Small and inviolable beats generous and negotiable. See flow and kanban debt for scheduling this work without sprint-shaped commitments.

Estimate in Ranges and Confidence, Not Points

A single number is a claim of precision you do not possess, and the moment it leaves your mouth it becomes a commitment. A range carries the uncertainty with it, and uncertainty is genuine information that a planner can use.

Attach a confidence level, because a range without one is still ambiguous. "Three to eight weeks, and I am about eighty percent confident it lands inside that" tells a stakeholder two things: the likely cost, and that there is a real chance of the upper end. It also converts the later conversation from "you were wrong" into "we landed in the tail we discussed", which is the difference between a blameless outcome and a broken relationship.

Let the Width Mean Something

A wide range is a signal, not sloppiness. If your range spans a factor of four, you are telling everyone that discovery has not happened yet -- and the correct response is to fund the spike, not to squeeze the range.

Resist the Single Number

Someone will ask you to collapse the range. If you must, give the upper end rather than the midpoint, and say why. Never let a midpoint be recorded as a date, because midpoints are wrong roughly half the time by construction.

Communicating Uncertainty Without Sounding Evasive

Engineers avoid ranges because ranges sound like hedging, and hedging sounds like incompetence. The fix is not more confidence. It is giving the stakeholder something concrete to hold on to in place of the false precision you took away.

Say This

"Comparable migrations here have taken six to fourteen weeks. I will know which end of that we are in after a two-week investigation, and I will come back with a range half as wide. If it looks like the top end, you will hear it in week two, not month three."

Not This

"It is hard to say, there are a lot of unknowns, it could be anything really." Both statements describe the same uncertainty. Only one of them offers a date on which the uncertainty will be smaller, and that is the entire difference between rigor and evasion.

Three habits carry most of the weight: name the reference class out loud so the number has visible provenance; commit to a date when the range narrows rather than to the range itself; and report movement early, because the cost of a bad estimate is almost entirely in how late it is discovered. For framing this in terms a budget owner responds to, see selling to management.

Track Your Own Error: The Only Calibration That Works

Every technique above depends on one input: knowing what your past estimates were and what the work actually took. Most teams do not have this, because the estimate is overwritten or forgotten the moment the ticket moves, and so the same error is repeated indefinitely with no feedback signal at all.

The instrument is embarrassingly simple. Record the original estimate, keep it immutable, record the actual, and look at the ratio in aggregate every quarter. Within a couple of quarters you will know your own multiplier, and it will be specific to your team, your codebase, and your category of work -- which is worth far more than any industry rule of thumb.

Freeze the Original

An estimate that gets revised mid-flight destroys the record. Keep the first number in a field nobody edits; track revisions separately as new estimates with their own dates.

Aggregate by Category

One overrun is noise. A pattern across a dozen dependency upgrades is a reference class, and it is the thing you will quote in your next planning meeting.

Review as a Team

Calibration data belongs to the team, not to individuals. The moment it becomes a per-person score it stops being calibration and becomes performance management, and the numbers stop being honest.

Punish Missed Estimates and You Buy Silence

Estimates are forecasts. A forecast that is treated as a promise stops being a forecast, because the person producing it now has an incentive that has nothing to do with accuracy.

What follows is predictable. Padding goes underground, so numbers inflate but nobody can say by how much, and the organization loses the ability to reason about capacity at all. Risk stops being reported, because raising a concern early looks like pre-excusing a failure -- so problems surface at the deadline instead of the moment they were known. And scope quietly shrinks to protect the date: tests get skipped, the migration ships half-finished, and the debt you were paying down comes back with interest.

The test: what happens to the person who says in week one that this is going to take three times longer than we thought? If they are thanked, your estimates will get better. If they are treated as the bearer of a failure, you have just taught everyone to wait until week nine, and no forecasting technique on this page will survive that.

Related Resources

Frequently Asked Questions

Because the unknowns are the work rather than a risk around it. A feature has a specification that bounds its surface area before you start. Debt work asks you to price the removal of something whose true shape only becomes visible once you begin removing it, and the discoveries along the way -- the undocumented caller, the behavior that turns out to be a customer contract -- are not exceptions to the task. They are the task.

You forecast from what comparable past work actually cost rather than from a decomposition of this one. In practice: pull the last eight or ten pieces of similar debt work out of your own tracker, classify them by shape rather than subject, record what each really took, and anchor the new forecast on that distribution. Adjust toward your bottom-up number only for reasons you can name out loud. "This time feels different" is not one of them.

It is better than nothing and much worse than measuring. A borrowed multiplier is somebody else's history applied to your codebase, your team, and your category of work, and it gives you no way to tell whether you are improving. Use it as a stopgap while you start recording original estimates and actuals, then replace it with the multiplier your own data produces. That number is specific to you, and it is defensible in a way a rule of thumb never is.

Give the stakeholder something concrete in place of the false precision you removed. Name the reference class so the number has visible provenance, attach a confidence level, and commit to a date on which the range will be narrower rather than to the range itself. Uncertainty plus a plan for reducing it reads as rigor. Uncertainty on its own reads as evasion, and the difference between the two is entirely in what you offer next.

Whenever the uncertainty cannot be reduced by thinking harder before starting. At that point an estimate is a guess wearing a number, and a fixed purchase of learning is more honest and more useful. Write the exit criteria in advance: what you will know, who decides, and which options are on the table. Then keep the box genuinely fixed, because a timebox extended twice teaches the team it was only ever another estimate.

You get silent padding, late risk reporting, and quietly shrinking scope. Numbers inflate but nobody can say by how much, so capacity planning degrades. Concerns stop being raised early because raising one looks like pre-excusing a failure, so problems surface at the deadline instead of when they were known. And the date gets protected by skipping tests and shipping the migration half-finished, which puts back more debt than the work removed.

Stop Guessing. Start Measuring Your Own Error.

Freeze the original estimate, record the actual, and let a quarter of your own history replace everyone else's rule of thumb.