Skip to content
Kumar Chandrachooda
Engineering Practice

The Maintainability Index and the Debt Ratio

The composite score that hides more than it shows and the percentage that translates code quality into money - where the maintainability index formula came from, why its logarithms flatten real problems, and how the technical debt ratio earns its place as a trend.

By Kumar Chandrachooda 25 Apr 2026 8 min read
A single green number resting on a pile of unpaid interest

Sooner or later, someone senior asks the question every engineering dashboard exists to dodge: “So what's our code quality, out of a hundred?” The complexity metrics from part 2 cannot answer it — they live inside single functions and refuse to aggregate into anything a steering pack would print. But the industry has an answer on the shelf, and it is even colour-coded: the maintainability index, a 0-to-100 composite that ships inside Visual Studio and turns whole modules green, yellow or red. This part is about what that number actually is, why trusting it standalone is a mistake with a precise mathematical cause, and which of its neighbours — the technical debt ratio and the duplication ratio — deserve the dashboard slot instead.

A formula from 1992, rebased for the IDE

The maintainability index is older than most codebases it now grades. It originates with Paul Oman and Jack Hagemeister, who proposed it in 1992 as a regression-fitted composite of the metrics that seemed, in their studies, to track maintainability. Microsoft later adopted a rebased variant for Visual Studio, rescaled to a tidy 0-to-100 range, and it is Microsoft's version you will meet in practice. The formula, as documented on Microsoft Learn:

MI = MAX(0, (171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln(LOC)) * 100 / 171)

Read the ingredients and you will recognise all three from the last part. HV is Halstead Volume — the retired soloist, still employed in the orchestra exactly as promised. CC is cyclomatic complexity. LOC is lines of code. Start from 171 points, subtract a penalty for vocabulary, a penalty for branching and a penalty for size, rescale, and clamp at zero. Visual Studio then applies the bands: 0 to 9 is red, 10 to 19 is yellow, 20 to 100 is green.

Notice what the composite is, structurally: three measurements and four coefficients. The measurements are honest. The coefficients — 5.2, 0.23, 16.2 — are a judgement call fitted to codebases studied more than three decades ago. A composite score is a decision someone else made about what matters, frozen into coefficients — and once you see the formula written down, you can work out exactly what that decision hides.

What the logarithms flatten

Two of the three penalties pass through a logarithm, and the third carries a coefficient of 0.23. Run the arithmetic on what that does to the score.

Take a function with a cyclomatic complexity of 10 — the top of the conventional “simple” band — and let it degrade to 40, deep into refactor-before-extending territory. The penalty term moves by 0.23 × 30, which after the 100/171 rescale is a loss of about four points. Four. A module can quadruple its branchiness and drift from 85 to 81, green before and green after, without the dashboard so much as flickering. Size fares little better: because LOC sits inside a logarithm, doubling a module's length costs roughly six and a half points regardless of whether it doubled from 50 lines to 100 or from 2,000 to 4,000 — and the second of those events is the one that should be setting off alarms.

That compression is the precise mechanical reason the maintainability index misleads as a standalone signal. It is not that the formula is wrong; it is that its output range is numb where your problems live. Nearly everything you will ever ship scores green, the score moves least exactly when the underlying metrics are moving most, and a reviewer who trusts the colour has effectively agreed not to notice gradual decay. The failure pattern from part 1 usually needs a target and an audience to corrupt a metric; the maintainability index manages to reassure falsely without either. In my own practice it survives in exactly one role — a coarse first-pass screen when I inherit an unfamiliar codebase, where sorting modules by ascending MI gives me a reading list for the afternoon. It ranks; it does not judge. Anything red is worth opening; everything green is unproven.

The ratio that speaks money

The second composite in this part earns its keep in a different currency. The technical debt ratio is the estimated effort to fix a codebase's known quality issues, divided by the estimated effort it took to build that code in the first place:

TDR = remediation cost / development cost * 100

The formula's virtue is entirely rhetorical, and I mean that as praise. A maintainability index of 62 means nothing to anyone outside the tooling; a technical debt ratio of 8% translates instantly for every audience in the room — for every hundred hours we invested building this, eight more are owed to problems we already know about. It is the only code-quality number I have ever put in front of a finance director without a glossary, and it reframes the remediation argument from “the engineers want to tidy up” to “here is the interest we are paying”.

Now the honesty that has to travel with it. Both sides of that fraction are estimates. The remediation figure is typically produced by a static-analysis tool pricing each detected issue with a fixed, catalogued fix time, and the development cost is derived from code size by convention — so the ratio is a model stacked on a model, not a measurement of anything. The grading scale on top is convention too: SonarQube awards its maintainability rating of A when the technical debt ratio is at or below 5%, and the wider bands you will meet — under 5% healthy, 5 to 10% needs attention, above 20% crisis — are tool and practitioner conventions, not findings from any study. None of this makes the ratio useless. It makes it a trend instrument: the absolute value is soft, but the direction and slope are real, because the estimation model's biases are at least consistent from quarter to quarter. A codebase whose TDR climbs from 4% to 9% across three quarters has genuinely degraded, whatever the true figures are — and that sentence, with a chart behind it, is the most productive opening a quarterly architecture conversation can have.

Duplication, the debt that compounds

If the debt ratio is the aggregate balance, duplication is the line item most worth watching individually — the percentage of the codebase that exists in more than one copy. Every duplicated block is a maintenance multiplier: the bug fix, the security patch, the changed business rule must all be applied once per copy, and the copy you miss becomes an inconsistency that ships. Unlike the maintainability index, this metric measures a direct cause of future cost rather than a statistical proxy for it.

The bands I hold it to — under 3% excellent, 3 to 5% acceptable, above 10% demanding active consolidation — are conventions of the same species as the TDR bands, and I present them as my working defaults, not as law. The measurement caveat matters too: detectors find structural similarity, and some repetition is legitimate — test arrangement code, configuration templates, wire-protocol scaffolding — so a raw percentage always deserves a skim of what it actually counted before anyone reacts to it.

There is also a fresh reason to watch this number more closely than we used to. GitClear's research on AI-assisted code quality, analysing 211 million changed lines of code from January 2020 to December 2024, found that the share of changed lines classified as copy/pasted rose from 8.3% to 12.3% between 2021 and 2024, while the share associated with refactoring sank from 25% of changed lines in 2021 to under 10% in 2024. Note the framing carefully — those are percentages of changed lines, a flow measure, not the duplication ratio of any codebase — but the direction is exactly what you would predict from generation tools that produce plausible new code more readily than they reuse existing abstractions. More copies in, fewer consolidations out: duplication ratios drift up by default now, which is why my quality gate treats a newly introduced duplicate block as a warning that requires a justification in review rather than a statistic to read about later.

Three instruments, one honest job description

Where this leaves the maintainability family on my own dashboard, offered as practice rather than industry standard: the maintainability index screens and never gates — a sorting key for triage, banned from quality gates and steering packs alike, because its compressed output range makes it reassurance theatre waiting to happen. The technical debt ratio appears quarterly, always as a trend line and never as a single figure, and always with the estimate caveat spoken aloud once per audience. Duplication is the one that earns a per-PR gate — warn on new duplicate blocks — because it is the one where the cause-and-effect link to future cost is direct enough to justify interrupting a merge. And none of the three ever says anything about a person; part 1's rule stands.

All three, though, share a blind spot: they grade code in place, file by file, as if modules lived alone. The most expensive structural problems do the opposite — they live in the dependencies between modules, where no per-file score can see them. Measuring the lines between the boxes needs a different toolkit entirely, and a 1994 paper supplies nearly all of it. Next: coupling, cohesion and the main sequence.