Find Hot-Spots to Fix First

The use-case Write Clean Code From Now On explains how NDepend can be used to avoid issues on new and refactored code since a baseline.

As all static analyzers, NDepend reports hundreds if not thousands of issues on a large legacy code base. To tackle this avalanche of issues NDepend proposes to:

Gamify issues fix with estimations and rates

The Dashboard Technical Debt and Coverage sections, found in Visual Studio extension in the report and in the Azure DevOps extension, show actual numbers and their delta since baseline.

The technical debt is an estimation of the cost to fix an issue, expressed in human-time. The code coverage data is imported from your preferred coverage technology: Visual Studio coverage, NCrunch, dotCover, NCover or OpenCover.

Dashboard Technical Debt and Code Coverage Sections

The Dashboard Debt section rates the code base quality. The rate is in the range A, B, C, D, E. This rate is inferred from the SQALE technical debt ratio that is a ratio between:

  • The cost estimation to fix issues (the technical-debt expressed in human-time)
  • The effort estimation that has been spent to develop the entire code base (expressed in human-time)

Note that effort and cost estimations come from carefully though out formula embedded in each rule. For example the formula embedded in the default rule Code should be tested takes account of various estimated factors that are then multiplied together. So far we received many positive feedback from users about the accuracy of the estimations inferred from default-rules.

let effortToWriteTests = Math.Max(2, // Minimum 2 minutes per method not tested
      effortToDevelopInMinutes *
      uncoverageFactor *
      complexityFactor *
      justMyCodeFactor *
      abstractionUsageFactor *
      visibilityFactor *
      staticFieldUsageFactor).ToMinutes().ToDebt()

In the dashboard, an estimation of the cost to improve the rate (for example from D to C) is shown. This gamifies fixing code smells and improving the overall code quality and maintainability.

Prioritize which issues found on existing code should be fixed first

Imagine a dirty code smell like a global state read and assigned from a bit everywhere in the code. With modern refactoring tools this code smell could be fixed in 2 hours. However as long as it is let unfixed, such code smell slows down the development because it is error-prone and forces developers to carefully think each time this popular state is concerned. For example suppose that this code smell slows down the development by 12 human-hours per year.

In this situation, in 2 months from now, the cost for fixing this code smell (2 hours) equals the cost of not fixing it (12 hours per year). Certainly it is worth fixing this code smell as soon as possible.

This example illustrates how NDepend prioritizes which issues found on existing code should be fixed first

  • The estimation of the cost to fix an issue (2 hours) is the technical-debt estimation.
  • The estimation of the cost per year for not fixing an issue (12 hours per year) is the annual interest estimation. More annual interest means higher issue severity.
  • In 2 months from now, the cost for letting the code smell unfixed equals the cost of fixing it. This duration, 2 months, is the ratio between the technical debt and the annual interest. This 2 months value represents the breaking point value of the code smell.

In this context issues with low breaking point values are good candidate to be fixed first. These issues represent the biggest bang for your bucks invested in improving the code quality.

We saw that the technical-debt estimation is obtained from a formula embedded in the rule. The same way the annual interest estimation is also obtained from a second formula embedded in the rule. For the default rule Code should be tested this formula looks like:

let annualCostToNotFix = Math.Max(2, // Minimum 2 minutes per method not tested
          effortToDevelopInMinutes *
          usageFactor *
          uncoverageFactor *
          justMyCodeFactor).ToMinutes().ToAnnualInterest()

The menu Dashboard > Debt > Types to Fix Priority lists classes whose issues have the lowest breaking point.

Menu: Types to Fix Priority

Types to Fix First

Identify hot-spots in terms of poor code quality

In the dashboard menus shown on the screenshot above we can also see the menu Types Hot Spots. Similarly to Types to Fix Priority this menu lists all types, but ordered with highest cost-to-fix first. Hot-spots shouldn't necessarily be fixed first. But knowing where hot-spots are and quantifying them is a useful knowledge. This can help convincing the management to get the resources to refactor some rotten code that annoys everyone in the team for a while.

Types with Highest Technical Debt Estimation First