Maintainability Index metric (LC0007)
This rule reports the calculated Maintainability Index for every procedure and trigger, allowing developers to identify areas that may benefit from refactoring. The companion rule LC0008 triggers a warning when the index falls below a configurable threshold.
What is the Maintainability Index?
The Maintainability Index (MI) is a composite software metric that quantifies how easy a piece of code is to understand, modify, and maintain. It condenses several lower-level measurements into a single score on a 0–100 scale, where higher values indicate more maintainable code.
The metric was originally proposed by Paul Oman and Jack Hagemeister at the University of Idaho in 1991, presented at the International Conference on Software Maintenance (ICSM 1992), and later refined in a paper published in IEEE Computer. Microsoft adopted the formula into Visual Studio, normalizing it to the 0–100 range that is widely used today — including by this analyzer.
Why it matters for AL development
Business Central AL extensions often have a long lifespan. Code written today may be maintained through multiple major version upgrades and by developers who did not author it originally. Tracking the Maintainability Index helps teams:
- Detect deteriorating code early — before a procedure becomes too expensive to safely change.
- Prioritize refactoring — by surfacing the procedures with the lowest scores.
- Guard upgrade readiness — complex, low-MI procedures are disproportionately likely to cause issues during version upgrades.
- Support onboarding — new team members can ramp up faster on well-structured code.
Scoring scale
The analyzer uses the Microsoft color-coded rating bands:
| Score | Rating | Meaning |
|---|---|---|
| 20 – 100 | 🟢 Green | Good maintainability |
| 10 – 19 | 🟡 Yellow | Moderate maintainability — consider reviewing |
| 0 – 9 | 🔴 Red | Low maintainability — refactoring recommended |
A score of 20 or above generally indicates code that is straightforward to work with. Scores below 10 signal procedures that are likely to be expensive and risky to change.
How the Maintainability Index is calculated
The analyzer uses the Microsoft normalized formula, which scales the result to a 0–100 range:
MI = MAX(0, (171 − 5.2 × ln(HV) − 0.23 × CC − 16.2 × ln(LOC)) × 100 / 171)
Where:
- HV = Halstead Volume
- CC = Cyclomatic Complexity
- LOC = Lines of Code
Note: The original 1992 formula included a comment-density factor (
+ 50 × sqrt(2.46 × perCOM)). This analyzer does not include comment density, consistent with Microsoft’s Visual Studio implementation.
Halstead Volume
Halstead Volume measures the “size” of a program in terms of operators and operands. It represents the amount of information a reader must absorb to understand the code.
In the AL implementation the analyzer counts:
| Category | AL examples |
|---|---|
| Operators | Keywords (if, begin, end, repeat, …) and tokens (+, -, :=, <>, …) |
| Operands | Identifiers (variable and function names), integer literals, string literals, boolean values (true, false) |
Halstead Volume is calculated as:
HV = N × log₂(n)
Where N is the total count of operators and operands and n is the count of unique operators and operands.
Cyclomatic Complexity
Cyclomatic Complexity counts the number of independent paths through a procedure. In AL, the following constructs each add one to the complexity count:
if, else if, and, or, for, foreach, while, until, each case line, and ternary (?:) expressions.
Every procedure starts with a base complexity of 1.
For a deeper explanation, see LC0009 — Cyclomatic Complexity metric .
Lines of Code
Lines of Code (LOC) counts the physical lines inside the procedure body, excluding the begin and end keywords. Longer procedures receive a lower Maintainability Index because more code generally means more to understand and more potential for errors.
Configuration
You can adjust the threshold at which LC0008
reports a warning by adding a MaintainabilityIndexThreshold property to the alcops.json file in your project root:
{
"MaintainabilityIndexThreshold": 20
}
The default threshold is 20, meaning procedures that score at or below 20 will trigger a warning.
See Configuration for all available settings.
History and background
The Maintainability Index originated as an internal project at Hewlett-Packard in the early 1990s. Engineers rated 16 projects on a maintainability scale, and regression analysis over more than 50 models produced the initial formula. The original equation ranged from 171 down to potentially unbounded negative numbers, which made low scores difficult to interpret.
In 2011, Microsoft introduced the normalized version used by this analyzer. The formula was clamped to the 0–100 range (MAX(0, … × 100 / 171)) and the comment-density term was removed, making the metric simpler and more consistent across codebases.
Limitations
Like any single metric, the Maintainability Index has limitations worth keeping in mind:
- Heavily influenced by code length — Lines of Code affects the result directly and indirectly through Halstead Volume. Splitting a procedure into helpers will improve MI even if overall complexity stays the same.
- Based on averages — The metric may mask a single extremely complex section within an otherwise simple procedure.
- Language-agnostic origin — The coefficients were derived from C projects at HP. They provide useful directional guidance for AL, but are not specifically calibrated for it.
- Not a complete picture — MI does not capture naming quality, architectural fitness, domain correctness, or how well the code integrates with Business Central patterns.
Use the Maintainability Index as one signal among many. A low MI is a strong hint that a procedure deserves attention, but a high MI alone does not guarantee good design.
Related content
- Code Metrics — Maintainability Index range and meaning — Microsoft Learn
- Calculating the Maintainability Index — Sourcery
- Classic Maintainability Index — ObjectScript Quality
- Measurement of Maintainability Index — Verifysoft
- Maintainability Index — BlueGrid