Maintainability Index
Composite 0-100 score (Oman & Hagemeister) combining cyclomatic complexity, Halstead volume, and lines of code.
The Maintainability Index, formalized by Oman & Hagemeister (1992) and standardized through Microsoft Visual Studio's Code Metrics, captures three independent drivers of maintenance cost in one number: control-flow complexity (cyclomatic), expression density (Halstead volume), and sheer file size (lines of code).
The formula MI = 171 − 5.2×ln(V) − 0.23×CC − 16.2×ln(LOC), scaled to 0-100, weighs LOC most heavily — large files are the most predictable drag on maintainability — followed by volume, then complexity. The composite is more stable than any individual metric: a file can game cyclomatic complexity by inlining branches, but the volume and LOC terms will still penalize the resulting density.
Severity guide
- info
- Rating A or B (>65). File is maintainable with normal review effort.
- warning
- Rating C or D (10-65). Changes carry meaningful risk; proactive refactoring recommended.
- critical
- Rating F (<10). File is at the most difficult end of the maintainability spectrum; immediate decomposition advised.
Examples
Before
// 600 LOC file with 15 cyclomatic and dense expressions throughout
export function orchestrate(input, opts, ctx) {
// ... many nested branches and inline transformations
}After
// Decomposed into focused modules
// orchestrate.ts (80 LOC, cyclomatic 5)
// parse-input.ts (60 LOC, cyclomatic 3)
// apply-transformations.ts (80 LOC, cyclomatic 4)
// format-output.ts (40 LOC, cyclomatic 2)Splitting a single large file into focused modules reduces each module's LOC and complexity components below their penalty thresholds, lifting the overall MI score from F into B or A territory.
Remediation
Identify the dominant penalty component (volume, complexity, or LOC) and refactor toward reducing that one first.
- Read the dominant-factor insight; it identifies which of the three components is dragging the score down most.
- Volume-dominant: extract repeated expression patterns into named helpers, prefer descriptive variable names that don't need inline comments.
- Complexity-dominant: replace nested conditionals with early returns, move large switch blocks to lookup tables, extract boolean conditions into named predicates.
- LOC-dominant: identify cohesive groups of functions and extract them into a dedicated module. Even moving a third of the file's logic out can move the MI rating up a grade.
- Re-run analysis after each refactoring pass; a single significant extraction often yields more improvement than many micro-edits.