-
Notifications
You must be signed in to change notification settings - Fork 0
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.
| 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.
| 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.
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 of0.3is also not part of the original principle — it is a configurable parameter.
These metrics are based on verified sources:
- Low coupling / High cohesion in Android — Guide 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.
- DAGP — dependency-analysis-gradle-plugin. Inspired the detection of misconfigured scopes.
- Cycle detection — DFS with node coloring (white/gray/black).