Code Metrics

Code metrics are quantitative measurements of software source code used to assess quality, complexity, maintainability, and risk. The most durable insight about metrics comes from Goodhart’s Law: when a measure becomes a target, it ceases to be a good measure. Metrics serve as signals to guide human judgment, not as optimization targets. A team that chases 100% test coverage while writing meaningless assertions has achieved the metric and destroyed its value.

Used correctly, metrics help identify code that warrants closer inspection — not code that is definitively bad. High cyclomatic complexity doesn’t mean a function is wrong; it means a reviewer should look carefully at its test coverage and consider whether refactoring would reduce cognitive load.

Common Metrics

Cyclomatic Complexity

Counts the number of linearly independent paths through a function (branches: if, for, while, case, &&, ||). A function with complexity 1 has no branches; complexity 10+ is hard to test thoroughly. McCabe’s original guideline: keep methods below 10. Modern tools (ESLint’s complexity rule, SonarQube) enforce configurable thresholds.

Lines of Code (LOC)

The oldest metric and among the most misused. Large LOC counts correlate loosely with maintenance burden, but LOC as a productivity measure (“story points per line”) is actively harmful. Useful primarily as a relative size indicator — a 2000-line file in a codebase where all others are under 200 lines warrants investigation.

Cognitive Complexity

A refinement of cyclomatic complexity (introduced by SonarSource) that penalizes nesting depth and rewrites more than branches alone. Better predicts human comprehension difficulty than pure branch counts. Two nested if statements add more cognitive load than two sequential ones.

Code Coverage

The percentage of production code executed by the test suite. Three coverage variants matter in practice:

  • Line coverage — easiest to achieve, least meaningful
  • Branch coverage — every if/else path executed
  • Mutation coverage — tests actually detect bugs when code is subtly changed (most rigorous)

80% branch coverage is a common threshold. Gaps in coverage are more important than the aggregate number — a single untested branch in a payment processor matters more than a 20% gap in a logging utility.

Coupling and Cohesion

Afferent coupling (Ca) — how many modules depend on this one. High Ca means changes here have wide blast radius.

Efferent coupling (Ce) — how many modules this one depends on. High Ce means this module is fragile to changes elsewhere.

Instability (I = Ce / (Ca + Ce)) — modules that are heavily depended upon should be stable; modules that depend on many others can afford to be unstable.

Cohesion — the degree to which elements within a module belong together. High cohesion (elements serve a unified purpose) is desirable; low cohesion (a “utility” or “helper” module with unrelated functions) is a code smell.

Using Metrics Effectively

  • Set thresholds to trigger review, not automatic failure (except in egregious cases)
  • Track trends over time: rising complexity in a module is more actionable than a snapshot
  • Use coverage gaps to direct testing effort, not coverage totals to declare success
  • Pair with human judgment: metrics identify candidates for review, not verdicts

Key Concepts

  • Metrics are signals, not verdicts — they direct attention, not decisions
  • Goodhart’s Law applies: optimizing for a metric degrades it as a quality signal
  • Cyclomatic and cognitive complexity measure testability and comprehension difficulty
  • Coverage gaps matter more than aggregate coverage numbers
  • Coupling metrics identify change risk; cohesion metrics identify design quality
  • Code Reviews — metrics can focus reviewer attention on high-risk areas
  • Code Inspection — defect density from inspections feeds back into module risk metrics
  • Design by Contract — contract assertions can be instrumented to track precondition/postcondition violation rates
  • Single Responsibility — modules with clear responsibility tend to have better cohesion metrics
  • Small Functions — smaller functions naturally have lower cyclomatic complexity

References

  • Fenton, N., & Bieman, J. (2014). Software Metrics: A Rigorous and Practical Approach (3rd ed.). CRC Press.
  • McCabe, T. J. (1976). A Complexity Measure. IEEE Transactions on Software Engineering.
  • Campbell, G. A. (2018). Cognitive Complexity: A New Way of Measuring Understandability. SonarSource.