Skip to content

Assessing technical debt

Technical debt accumulates silently — a quick fix here, a skipped refactoring there — until it slows every feature to a crawl. This investigation walks through a data-driven approach to identify, measure, and prioritize technical debt in your codebase using Software Metrics Machine, so you can make backlog decisions backed by evidence rather than intuition.

Target project

The project used is json-tool, an open-source project with moderate activity and a multi-file structure that provides enough source code data for a realistic technical debt assessment.

Data collection

Source code metrics are extracted from the local git repository using CodeMaat. The repository must be cloned locally — the analysis reads the git history directly, not a provider API.

Fetch code metrics

bash
smm code codemaat-fetch --start-date 2025-08-17 --end-date 2025-11-17

This extracts revision history, churn, coupling, and ownership data from the local git repository over the three-month window. The data is cached so subsequent commands read from disk unless you pass --force.

For repositories with deep directory structures, use --group-depth to control aggregation layers in coupling analysis:

bash
smm code codemaat-fetch \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --group-depth 2

Raise the coupling sensitivity thresholds on larger codebases to filter out noise:

bash
smm code codemaat-fetch \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --min-coupling 50 \
  --min-revs 10 \
  --min-shared-revs 10

Fetch commits

For deeper change-set analysis, fetch the raw commit data alongside the CodeMaat metrics:

bash
smm code fetch-commits --start-date 2025-08-17 --end-date 2025-11-17

Setting the analysis scope

Large codebases contain generated files, vendored dependencies, and test fixtures that produce noise in technical debt metrics. Filter them out with ignore patterns available on every analysis command:

bash
--ignore_files="*.min.js,dist/**,node_modules/**"

Conversely, use include patterns to narrow the analysis to a specific subsystem:

bash
--include_only="src/compute/**,src/storage/**"

Analysis

With the data in place, run the commands below. Each command reads the cached data — no git operations are needed unless you force a re-fetch.

Entity churn: change hotspots

Entity churn identifies which files change most often — the primary signal for hotspots. Files that change frequently are statistically more likely to contain defects and accumulate technical debt[^1][^2].

bash
smm code entity-churn \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --top 10

Example output:

text
                        file  added  deleted
0     src/parser/engine.ts    245       80
1       src/utils/serial.ts    198      120
2        src/types/config.ts    170       45
3     src/api/handler/auth.ts   155       90
4         src/models/user.ts   130       35

A file appearing in the top 10 across consecutive quarters is a confirmed hotspot. Research shows that modules in the top quartile of change frequency contain 2–5x more post-release defects than stable modules[^1][^3]. The metric captures both feature work (high added lines) and refactoring (balanced added/deleted lines). A file with low additions but high deletions suggests debt-reduction work — a positive signal[^4].

Entity effort: development concentration

Entity effort measures how many commits touch each file, revealing where development attention is concentrated. When effort is concentrated in a handful of files while the rest of the codebase goes untouched, those high-effort files become single points of risk[^5].

bash
smm code entity-effort \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --top 10

Example output:

text
                        file  revisions
0     src/parser/engine.ts         34
1      src/api/handler/auth.ts      28
2       src/utils/serial.ts         24
3        src/models/user.ts         20
4      src/types/config.ts          17

Cross-reference effort with churn. A file high in both churn and effort is a development bottleneck — it absorbs disproportionate attention and impedes parallel work. A file high in effort but low in churn may be a frequently touched configuration or glue file that requires constant adjustment without substantial code change.

The distribution matters as much as the top entries. If 80% of commits touch only 20% of files, your team is working in a narrow slice of the codebase. That narrowness concentrates knowledge and increases the risk that changes in any one of those files cascade into regressions elsewhere[^6].

Entity ownership: knowledge concentration

Ownership shows who contributed to each file. Concentrated ownership — one author responsible for the majority of changes to a file — is the strongest process-level predictor of post-release defects[^6][^7].

bash
smm code entity-ownership \
  --start-date 2025-08-17 \
  --end-date 2025-11-17

Example output:

text
                        file          author  lines_changed
0     src/parser/engine.ts          alice            325
1     src/parser/engine.ts            bob             45
2       src/utils/serial.ts          alice            318
3        src/types/config.ts        charlie            215
4        src/types/config.ts          alice             55

For each critical file, ask two questions:

  • Is the primary contributor still on the team? If not, the file has zero active owners — a bus-factor-1 risk that has already materialized. These files are your highest-priority knowledge transfer targets[^7].
  • Do more than 75% of changes come from a single author? This is a knowledge silo. If that author leaves or moves to another team, the file becomes orphaned. Cross-training and pair rotation on high-ownership files reduces defect density by up to 30% compared to siloed ownership[^6].

Coupling: architectural entanglement

Coupling identifies files that change together across commits. When two files that should be independent always change together, they are coupled — a form of architectural technical debt known as shotgun surgery[^8]. Tightly coupled modules resist isolated change, making every modification riskier and more expensive.

bash
smm code coupling \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --min-coupling 0.3

Example output:

text
                   entity             coupled   degree
0     src/parser/engine.ts    src/types/config.ts      75
1    src/api/handler/auth.ts   src/models/user.ts      68
2      src/utils/serial.ts     src/parser/engine.ts     55
3     src/api/handler/auth.ts  src/types/config.ts      42

The coupling degree is the percentage of commits to one file that also touch the other. Three patterns to watch:

PatternExampleSignal
Bidirectional high couplingengine.ts ← 75% → config.tsThe files are logically inseparable. Consider merging them or introducing a shared abstraction. Cow-changed files are 3x more likely to contain defects than independently changed files[^9].
Unidirectional couplinghandler/auth.ts → 68% → models/user.ts, but not vice versaThe first file depends on the second, but the second is independent. This is normal layering — but verify that the dependency direction matches the intended architectural boundary.
Accidental couplingutils/format.tsclient/login.tsNo logical connection between the files but they change together. Often indicates a shared constant, import, or test fixture that should be extracted to a shared location. Accidental coupling is the most common source of unintended side effects[^10].

Temporal coupling — files that change together over time — is distinct from structural coupling (imports, dependencies). Both matter, but temporal coupling reveals architecture violations that static analysis cannot detect[^8][^10].

The --min-coupling threshold controls sensitivity. On large repositories (> 500 files), start at 0.5 to surface only the strongest couplings. On smaller repos, 0.3 exposes relationships worth investigating.

Big O classification: algorithmic risk

Algorithmic complexity that grows super-linearly is a specific, measurable form of technical debt. Big O classification scans source files for patterns indicating O(n²), O(n³), or worse complexity, assigning each file a risk score.

bash
smm code big-o \
  --limit 50 \
  --ignore-files "*.test.ts,*.spec.ts"

Example output:

text
                        file  classification  score
0      src/parser/engine.ts          O(n²)      85
1     src/api/aggregate.ts           O(n²)      70
2       src/utils/search.ts          O(n³)      95
3    src/services/process.ts         O(n²)      55
4     src/models/schedule.ts         O(n²)      40

Files with O(n²) or higher complexity are candidates for algorithmic review. The score reflects both the severity of the detected pattern and the confidence in the classification. A file scoring above 70 with O(n³) imposes a measurable performance cost that grows with input size.

To understand why a file received its classification, drill into line-level analysis:

bash
smm code big-o --file src/parser/engine.ts

This shows which specific lines trigger the complexity detection. Use it to scope refactoring work to the exact loops or recursive calls responsible for the classification.

Code churn: development rhythm

Code churn measures daily lines added and deleted across the entire repository. It serves as the baseline signal for overall development activity and helps contextualize the entity-level metrics.

bash
smm code churn \
  --start-date 2025-08-17 \
  --end-date 2025-11-17

Example output:

text
          date  added  deleted
0  2025-08-17    340       50
1  2025-08-18    120      200
2  2025-08-19    560       30
3  2025-08-20     80       75

A day with balanced additions and deletions (e.g., 2025-08-18: 120 added, 200 deleted) typically indicates refactoring. A day dominated by additions (e.g., 2025-08-19: 560 added, 30 deleted) indicates feature work. If refactoring days are rare relative to feature work days, debt is accumulating — codebases that add lines without periodically removing them grow linearly in maintenance cost[^11].

Pairing index: knowledge sharing

The pairing index — the percentage of commits with multiple authors — measures how broadly knowledge is distributed across the team. Low pairing indices correlate with concentrated ownership and higher defect rates in files owned by a single developer[^7][^12].

bash
smm code pairing-index \
  --start-date 2025-08-17 \
  --end-date 2025-11-17 \
  --min-shared 2

Example output:

text
                  name    value  count
0           alice-bob      12       3
1        alice-charlie      8       2
2          bob-charlie      4       1
Pairing index: 34.5%

The pairing index is calculated as the percentage of commits with at least one co-author, relative to total commits. Teams that pair or co-author regularly tend to have pairing indices above 50%. Indices below 20% suggest isolated work patterns — each developer is primarily working alone, which concentrates knowledge and increases the risk that absences become blockers[^12].

Pairing data also reveals who pairs with whom. If the top pair is the same two people across every period, the broader team is not sharing knowledge effectively. Rotate pairings to distribute expertise.

Reading the results together

Running each metric in isolation gives you lists. Connecting them gives you a technical debt triage framework — a practice grounded in empirical research on software maintainability and defect prediction[^1][^6][^8].

Start by generating a combined view of your hotspots:

bash
smm code entity-churn --start-date 2025-08-17 --end-date 2025-11-17 --top 20

smm code entity-effort --start-date 2025-08-17 --end-date 2025-11-17 --top 20

smm code coupling --start-date 2025-08-17 --end-date 2025-11-17 --min-coupling 0.3

smm code entity-ownership --start-date 2025-08-17 --end-date 2025-11-17

With all four tables in front of you, cross-reference them to identify which files need attention and why.

Churn vs effort: the hotspot quadrants

Map each file onto two axes — total churn (lines changed) and effort (commit count) — to classify it into one of four quadrants.

ChurnEffortQuadrantWhat it meansAction
HighHighActive hotspotThe file absorbs both attention and change. It is central to active development but unstable.This is the highest-priority debt target. Investigate whether the file's responsibilities are too broad. Consider splitting it into smaller, more focused modules[^1].
HighLowBrittle churnFew commits, but each one changes many lines. Often a large auto-generated file, a third-party integration, or a data file that gets wholesale replacement.Verify the file is not generated. If it is, exclude it from analysis. If it is hand-maintained, it is a single point of failure that changes in big, risky chunks.
LowHighConfiguration gateMany small commits, few lines each. Typically a config file, build script, or feature flag that requires constant toggling.If it is a config file, consider externalizing configuration so code changes are not required. If it is a build script, stabilize it — build churn is associated with CI instability[^13].
LowLowStableThe file is mature and rarely changed.This is the target for most files. Monitor for unexpected movement into other quadrants.

Churn vs ownership: the knowledge risk matrix

Overlay entity ownership data to assess the bus-factor risk for each hotspot.

ChurnOwnershipWhat it meansAction
HighConcentrated (> 75% one author)Critical knowledge silo. A high-churn file that only one person understands. If that person is unavailable, changes are blocked and quality drops.Immediately assign a second developer to the file area. Pair-program or co-author on changes until at least one other developer has submitted 25%+ of recent changes[^6].
HighDistributedShared hotspot. The team is sharing the pain, which reduces individual risk.Still prioritize refactoring or splitting, but knowledge risk is mitigated.
LowConcentratedLegacy expertise. A stable file maintained by one expert. Low immediate risk, but a bus-factor time bomb.Schedule cross-training during the next change to this file. The cost of knowledge transfer on a stable file is low — do it before it becomes a hotspot[^7].
LowDistributedHealthy maintenance.Document and move on.

Coupling vs churn: the entanglement debt

Coupling between high-churn files creates a compounding risk: when one hotspot changes, the other must change with it, doubling the surface area for defects[^8][^10].

ChurnCouplingWhat it meansAction
HighHighEntangled hotspot. Two or more high-churn files that always change together. Each change to one forces a coordinated change to the other.Extract the shared concern into a third module that both depend on. This is the classic "introduce an abstraction" refactoring. Research shows that files connected by a mediating abstraction have 40% lower defect correlation than directly coupled files[^9].
HighLowIndependent hotspot. The file changes frequently but independently — its changes do not cascade.The hotspot is localized. Refactor within the file rather than restructuring module boundaries.
LowHighLegacy coupling. Stable files that are coupled. The coupling may be accidental (e.g., shared test fixtures) or intentional (shared library).Audit the coupling direction. If the dependency flows from the stable file to the coupled file (and not vice versa), it is healthy. If it is bidirectional, decouple before one of the files becomes a hotspot.
LowLowIndependent and stable.Expected. No action needed.

Pairing vs ownership: the collaboration health check

The pairing index provides the systemic context for ownership data.

Pairing indexOwnership concentrationWhat it meansAction
Low (< 20%)HighIsolated silos. Developers work alone on files they own. Knowledge is not flowing between team members.Introduce pair programming sessions on high-ownership files. Even short, focused pairing sessions on high-churn files reduce knowledge concentration measurably[^12].
Low (< 20%)LowIndependent work on shared code. Authors touch many files but rarely collaborate. The risk is coordination failures — two people changing the same file without awareness.Increase communication around shared files. Consider CODEOWNERS rules or automated notifications when a file is modified concurrently.
High (> 50%)HighHigh pairing on a few files. The team pairs actively, but only on a subset of files. The files outside the pairing circle remain siloed.Extend pairing to the un-paired files, especially those in the high-churn quadrant.
High (> 50%)LowHealthy knowledge distribution.Document the pairing practices that work and reinforce them. Teams with high pairing indices and distributed ownership resolve defects 30% faster than teams with siloed expertise[^6][^12].

The technical debt triage matrix

Combine all four dimensions into a single triage framework. For each file in the top-20 entity churn list, score it on three axes:

  1. Change risk (churn percentile + effort percentile) — how much the file absorbs the team's attention.
  2. Knowledge risk (ownership concentration + pairing index context) — how fragile knowledge of the file is.
  3. Architectural risk (coupling degree to other top-20 files) — how much the file's changes cascade.
Combined riskSignalAction
High on all threeEmergency. The file is a bottleneck, a knowledge silo, and an entanglement hub.Allocate dedicated refactoring time. This file is costing more in coordination, defects, and delay than it would cost to restructure. Studies show that files in this category account for 60–80% of post-release defects in their module[^1][^3].
High on twoWarning. The file has compound debt but is manageable.Schedule debt reduction in the next iteration. Focus on the risk axis that is most expensive — if knowledge risk is the highest, pair on it; if architectural risk is the highest, decouple it.
High on oneMonitor. Standard technical debt.Track the file over time. If it moves into a second risk category, escalate.
Low on all threeHealthy.Baseline recorded.

Quick decision checklist

After running the commands above, walk through these five questions with the combined data:

  1. Does the same file appear in the top 5 of both entity-churn and entity-effort? → Active hotspot. Split or refactor[^1].
  2. Does any critical file have more than 75% ownership by a single author? → Knowledge silo. Cross-train immediately[^6].
  3. Are any coupled files both in the top-10 churn list? → Entangled hotspots. Extract a shared abstraction[^8][^10].
  4. Is the pairing index below 20% with concentrated ownership? → Collaboration gap. Introduce pairing on high-risk files[^12].
  5. Does the Big O scan show O(n²) or worse in high-churn files? → Algorithmic debt. The performance cost grows as the codebase does — address it before it becomes a production incident.

References

[^1]: Nagappan, N., Ball, T., & Zeller, A. (2006). Mining metrics to predict component failures. Proceedings of the 28th International Conference on Software Engineering (ICSE), 452–461. ACM. — Change frequency is the strongest single predictor of defect-prone modules.

[^2]: Tornhill, A. (2015). Your Code as a Crime Scene: Use Forensic Techniques to Arrest Defects, Bottlenecks, and Bad Design in Your Programs. Pragmatic Bookshelf. — Introduces the hotspots methodology combining revision frequency with complexity.

[^3]: Ostrand, T. J., Weyuker, E. J., & Bell, R. M. (2005). Predicting the location and number of faults in large software systems. IEEE Transactions on Software Engineering, 31(4), 340–355. — Files in the top 20% by change frequency contain approximately 80% of defects.

[^4]: Zimmermann, T., Nagappan, N., & Zeller, A. (2008). Predicting defects from program history. In Software Evolution (pp. 75–86). Springer. — Churn metrics alone outperform static complexity metrics for defect prediction.

[^5]: Hassan, A. E. (2009). Predicting faults using the complexity of code changes. Proceedings of the 31st International Conference on Software Engineering (ICSE), 78–88. IEEE. — The entropy of changes (how widely modifications are distributed) predicts faults better than code complexity metrics.

[^6]: Bird, C., Nagappan, N., Murphy, B., Gall, H., & Devanbu, P. (2011). Don't touch my code! Examining the effects of ownership on software quality. Proceedings of the 19th ACM SIGSOFT Symposium on Foundations of Software Engineering (ESEC/FSE), 4–14. ACM. — High contributor concentration per file correlates with higher pre- and post-release defect rates. Distributed ownership reduces defect density.

[^7]: Nagappan, N., Murphy, B., & Basili, V. (2008). The influence of organizational structure on software quality: An empirical case study. Proceedings of the 30th International Conference on Software Engineering (ICSE), 521–530. ACM. — Organizational metrics (ownership, coordination) are stronger defect predictors than traditional code complexity metrics.

[^8]: Cataldo, M., & Herbsleb, J. D. (2011). Factors leading to integration failures in global feature-oriented development: An empirical analysis. Proceedings of the 33rd International Conference on Software Engineering (ICSE), 161–170. ACM. — Temporal coupling between files changes that are not architecturally related predicts integration failures.

[^9]: D'Ambros, M., Lanza, M., & Robbes, R. (2012). Evaluating defect prediction approaches: A benchmark and an extensive comparison. Empirical Software Engineering, 17(4), 531–577. Springer. — Change-coupling (co-change metrics) is among the top defect prediction approaches across multiple systems.

[^10]: Geiger, R. S., Varoquaux, N., Mazel-Cabasse, C., & Holdgraf, C. (2018). The types, roles, and practices of documentation in data analytics open source software libraries. Computer Supported Cooperative Work (CSCW), 27(3), 767–802. — Temporal coupling patterns reveal hidden architectural dependencies.

[^11]: Lehman, M. M. (1980). Programs, life cycles, and laws of software evolution. Proceedings of the IEEE, 68(9), 1060–1076. IEEE. — Lehman's second law: as a system evolves, its complexity increases unless work is done to maintain or reduce it.

[^12]: Begel, A., Nagappan, N., Poile, C., & Layman, L. (2009). Coordination in large-scale software teams. Proceedings of the 2009 ICSE Workshop on Cooperative and Human Aspects on Software Engineering (CHASE), 1–7. IEEE. — Teams with higher pair-commit rates exhibit lower defect density and faster issue resolution.

[^13]: Beller, M., Gousios, G., & Zaidman, A. (2017). Oops, my tests broke the build: An explorative analysis of Travis CI with GitHub. Proceedings of the 14th International Conference on Mining Software Repositories (MSR), 356–367. IEEE. — Build configuration churn is associated with increased CI failure rates.

Dashboard

The same metrics are available in the Source Code dashboard tab. After fetching the data, start the dashboard:

bash
smm dashboard serve

Then open http://localhost:3000/dashboard/code. The tab shows:

  • Code Churn Over Time: stacked bar chart of daily lines added (blue) and deleted (red), showing development rhythm and refactoring activity.
  • Entity Churn: top N most frequently changed files (hotspots) ranked by total churn.
  • Entity Effort: treemap where each rectangle's size represents the number of commits per file, surfacing development concentration.
  • Entity Ownership: stacked bar chart and tabbed views showing ownership by author, file, and entity — who contributed what to which file.
  • Code Coupling: graph showing relationships between files based on co-changes in commits.
  • Pairing: top author/co-author pairs by paired commit count and latest 20 paired commits.
  • Big O Classification: sortable table of files with detected algorithmic complexity and risk score, with search and line-level drill-down.

The Source Code tab supports date range, author, file include/exclude patterns, top-N, and churn type filters. See Dashboard for shared filter, timezone, and saved-view behavior.

Released under the MIT License.