I work for a company that is looking into this exactly. Below are 3 actionable metrics that we recommend to look at when tackling technical debt. For more information on "how" and "when" to track them, we put together a summary article 3 Metrics to Understand and Tackle Technical Debt.
What are your thoughts? Happy to answer any questions and hungry to hear your feedback :).
Ownership to prevent defects & unwanted tech debt
Ownership is a leading indicator of engineering health.
The parts of the codebase receiving contributions from many people accumulate cruft over time, while those receiving contributions from fewer people tend to be in a better state. It's easier to maintain high standards in a tight group that is well-informed about their part of the codebase.
This provides some predictive power: weakly owned parts of the codebase are likely to accumulate debt over time and become increasingly hard to work with. In particular, it's likely for debt to be unintentionally taken on, simply as a side-effect of incomplete information and diluted ownership of the code's quality.
This is somewhat analogous to the tragedy of the commons.
Cohesion to improve the architecture
Cohesion is a trailing indicator of well defined components.
Cohesion and its counterpart, coupling, have long been recognised as important concepts to focus on when designing software.
Code is said to have high cohesion when most of its elements belong together. High cohesion is generally preferrable because it's associated with maintainability, reusability, and robustness. High cohesion and loose coupling tend to go hand in hand.
Beyond being associated with more reusable and maintainable code, high cohesion also minimises the number of people who need to be involved to modify a given part of the codebase which increases productivity.
Churn to identify problem areas
Churn (repeated activity) helps identify and rank areas ripe for refactoring in a growing system.
As systems grow, it becomes harder for developers to understand their architecture. If developers have to modify many parts of the codebase to deliver a new feature, it will be difficult for them to avoid introducing side-effects leading to bugs, and they will be less productive because they need to familiarise themselves with more elements and concepts.
This is why it's important to strive for single responsibility to create a more stable system and avoid unintended consequences. While some files are architectural hubs and remain active as new features are added, it's a good idea to write code in a way that brings closure to files, and rigorously review, test, and QA churning areas.
Churn surfaces these active files so you can decide whether they should be broken down to reduce the surface area of change in your codebase.