Skip to content

Why these metrics

Every metric dowsing reports is a choice, and every choice has a source. This page is what those sources are, and — more usefully — where each metric stops being reliable.

Four things to hold onto

Before any individual metric, four caveats apply to all of them.

  1. The complexity proxies all correlate strongly with each other. LoC, indentation depth, cyclomatic, cognitive — as a first approximation for hotspots they rank things similarly. None is a complete stand-in for how hard code is to understand.
  2. "Coupling" has several competing definitions, differing in the denominator. Which one you use changes the numbers substantially. dowsing fixes one and says which.
  3. Most of these correlate with defects; they do not cause them. Treat them as a heuristic for prioritising, not as proof.
  4. Contamination of the history matters more than the precision of the formula. Untracked renames, formatting commits, squashes — these move the result further than any definitional detail. That is why Trusting the data exists.

Hotspots

The idea comes from Adam Tornhill: a hotspot is complex code you have to keep dealing with. It rests on older empirical work:

  • Graves et al. (2000, TSE) — the number of past changes predicts defects better than lines of code.
  • Nagappan & Ball (2005, ICSE) — relative code churn predicts defect density with high accuracy.

In the original framing this is a two-dimensional intersection rather than a fixed product. dowsing implements the product of the two normalised ranks, because a ranking is what a prioritisation tool has to produce.

Is LoC a legitimate stand-in for complexity?

At file level, largely yes. Jay et al. (2009) examined 1.2 million files and found cyclomatic complexity ≈ a·LoC + b with R² ≈ 0.90.

The important caveat: normalise per function and the correlation weakens. So LoC is fine for ranking files, and once a file matters you should descend to the function level — which is why dowsing health --file reports per-function numbers.

Change coupling

The concept is Gall et al. (1998, ICSM) (logical coupling), extended by Zimmermann et al. (2005, TSE) (association rules) and related to defects by D'Ambros et al. (2009, WCRE).

Writing |A| for the number of commits that changed A, and |A∩B| for commits that changed both:

SchoolDenominatorFormulaSymmetric
Tornhill / Code Maat / CodeScenemean2·|A∩B|/(|A|+|B|)yes
Zimmermann (confidence)|A||A∩B|/|A|no
Jaccardunion|A∩B|/(|A|+|B|−|A∩B|)yes
minmin(|A|,|B|)|A∩B|/min(|A|,|B|)yes

dowsing uses the symmetric Tornhill/Code Maat form by default and also reports the directional confidence. The choice matters: the same pair of packages can look very differently coupled depending on which row of that table you pick, so a tool that does not tell you which one it used is not giving you a number you can reason about.

Where the default thresholds come from

SourceMin revisionsMin sharedMin degreeLarge-commit cutoff
Code Maat5530%> 30 files
CodeScene101050%> 50 files
Zimmermann/ROSEsupport > 1confidence > 0.5> 30 entities

dowsing takes Code Maat's numbers with CodeScene's larger changeset cutoff. These are starting points, not truths. If nothing shows up at 30%, lower it — a pair at 26% with 90 co-changes is still telling you something.

Cognitive complexity

Campbell / SonarSource. The starting argument is that cyclomatic complexity was designed to measure testability and is a poor measure of understandability. Cognitive complexity is explicitly designed to put a number on programmer intuition.

Three rules:

  1. Ignore shorthand that makes multiple statements read as one.
  2. Add 1 for each break in linear flow.
  3. Add more for each level of nesting around such a break.
KindNesting bonusIncreases nestingExamples
Structuralyesyesif, for, while, catch, switch, ternary
Hybridnoyeselse if, else
Fundamentalnonological operator chains, recursion, labelled break

The practical consequence: a chain like a && b && c counts once, not per operator, and an if nested three deep costs far more than one at the top level. That is the behaviour you want from a metric that claims to track reading effort.

Code Health

dowsing's health score is deliberately not the Maintainability Index.

MI is a regression polynomial and has been criticised hard for opaque derivation (van Deursen, 2014): its inputs all correlate with size, and averaging hides the risky parts. Its coefficients also differ between sources. dowsing does not use it, and if you see an MI-style single number elsewhere, ask what it is made of.

Instead:

health = 10 − Σ(weight × severity)

Every term is visible, every weight is configurable, and the tool prints which smell cost how many points. It is a simpler model than MI, and the point is that you can check it.

Ownership and bus factor

Ownership by added lines, not by blame. git blame attributes a line to whoever touched it last, which credits a formatting pass over the person who wrote the logic. Counting added lines across the whole history is a more stable signal of who knows the code.

Minor contributor: below 5% ownership — from Bird et al., who found that a high number of minor contributors correlates with defects.

Bus factor follows Avelino et al. (ICPC 2016): compute a Degree-of-Authorship per developer per file, then greedily remove the developer who owns the most files until fewer than half the files still have an author. The DOA coefficients come from Fritz et al. (ICSE 2010).

DOA(d,f) = 3.293 + 1.098·FA + 0.164·DL − 0.321·ln(1 + AC)

This is a team risk indicator, not a performance review

Tornhill warns about this and so do we. "Bus factor 1" says a package's knowledge sits with one person. It does not say that person is doing anything wrong — usually the opposite.

The number is also fragile in one specific way: if a developer commits under several email addresses and your .mailmap does not merge them, dowsing counts them as separate people and overestimates the bus factor. The package looks safer than it is. That failure mode is silent, which is why it is worth stating plainly.

Further reading

Released under the MIT License