Skip to content

Sanity Metrics

pfranccino edited this page Jun 15, 2026 · 1 revision

Sanity Metrics

gradle-sanity computes three coupling metrics per module, detects anti-patterns, and summarizes everything into a 0–100 score. This page explains what each metric means and how it is calculated.

Ca, Ce, I

Column Meaning
Ca (afferent coupling) How many modules depend on this one (fan-in). High in common, core.
Ce (efferent coupling) How many modules this one depends on (fan-out). High in app or high-level features.
I (instability) Ce / (Ce + Ca). 0 = very stable, 1 = very unstable.

Dependency pyramid: modules with high I (features, app) sit "at the top" — they use others but nothing should depend on them (they are the leaves of the tree). Modules with low I (core, common) sit "at the bottom": everyone depends on them. Arrows should point from top (unstable) toward bottom (stable).

The report itself includes this glossary when it runs:

  I   (Instability = Ce / (Ce + Ca))
      I = 0.00 → very STABLE   (ideal for base modules: common, core)
      I = 1.00 → very UNSTABLE (ideal for leaf modules: app, features)

      ⚠️  The value of I is not inherently good or bad.
          What matters is the DIRECTION of the arrows:
          dependencies must point from high I → low I.

What it detects and how much it penalizes

Problem Default penalty Description
Cycle −20 pts A depends on B and B depends on A
SDP violation −10 pts Stable depends on unstable (I(target) − I(source) > 0.3)
Unnecessary api −5 pts Uses api but Ca=0
Excessive fan-out −3 pts Ce exceeds the threshold (default: 5)
Hardcoded version −2 pts "lib:x:1.2.3" instead of Version Catalog
Misplaced shared logic informative (configurable) A leaf (feature/app, high I) that other modules depend on (Ca above the limit)
Orphan modules informative No incoming or outgoing dependencies (Ca=0 and Ce=0)

Weights are configurable in analyzer_config.json under sanity_weights and coupling_limits — see Configuration.

Final score

  90–100 → 🟢 Excellent — very healthy dependency architecture
  70–89  → 🟡 Good — with minor areas for improvement
  50–69  → 🟠 Attention required in the architecture
   0–49  → 🔴 Urgent refactoring recommended

The 0–100 score is not an external standard. It is a guide with sensible default weights as a starting point, adjustable in analyzer_config.json. The SDP threshold of 0.3 is also not part of the original principle — it is a configurable parameter.

References

These metrics are based on verified sources:

  • Low coupling / High cohesion in AndroidGuide to Android app modularization · Common modularization patterns
  • Ca, Ce, I metrics and package coupling principles — formulated by Robert C. Martin (Uncle Bob) in Agile Software Development: Principles, Patterns, and Practices (2002), chapter on Package Design Principles. The three principles:
    • ADP (Acyclic Dependencies Principle) — the dependency graph must have no cycles.
    • SDP (Stable Dependencies Principle) — a module should only depend on modules more stable than itself.
    • SAP (Stable Abstractions Principle) — the most stable modules should be the most abstract.
    • The formula I = Ce / (Ce + Ca) quantifies stability: 0 = impossible to destabilize, 1 = completely unstable.
    • See also: Efferent coupling — Wikipedia · Software Coupling Metrics — entrofi.net
  • Application to Android modules — Martin defined these metrics for packages in Java/C++. In Android multi-module projects, each Gradle module plays the same role as a package (unit of compilation and encapsulation), so the semantics transfer directly.
  • DAGPdependency-analysis-gradle-plugin. Inspired the detection of misconfigured scopes.
  • Cycle detection — DFS with node coloring (white/gray/black).

Clone this wiki locally