NDepend – Measuring Technical Debt

I have been eager to get stuck into NDepend v2017 since it was recently released as there are new features which I think might make developers take another look at this useful tool which helps them quantify the quality of their code base, and with the latest release, its liabilities. If you’d like an introduction to NDepend you’re better of first reading an introductory blog post I wrote a while back. What I’d like to look at in this post is the the killer feature which caught my attention and that is technical debt estimation.

You’re probably thinking the same thing I did when I saw this in the feature listing. How the hell can you possibly quantify that? If you move past that thought and actually take a look you might be surprised. That’s what I set to find out.

A simple example of technical debt

There’s a saying I heard Mark Seemann once say, “You get what you measure” and it applies when calculating technical debt. What you’ll get out of this is exactly what you choose to measure and what it means to you. The rules which NDepend use are guided by SQALE which is a formalised study which allows you to quantify value of code and is language agnostic. Of course, you can ignore, customise and tweak these rules until it makes sense to you or your team.

Using these defaults, I ran it against a stock standard MVC application which is scaffolded by Visual Studio, essentially “File -> New Project”. After creating the project I ran NDepend against it and randomly chose the rule highlighted below.

Double click on the rule and be presented with the problematic types.

According to the query, defining multiple types in the same source file reduces readability and also reduces visibility within the Visual Studio Solution Explorer of all of the types available. It also bloats code files. The time required to fix this issue? 3 minutes per type in a source file that contains many types. I would probably argue less time than that, and that’s where you can tweak the query to your liking.

With modern tooling placing a type into another source file takes seconds so I thought I’d tweak the rule to be 10 seconds to extract each type.

Yay! 40 seconds to fix all 4 issues costing my employer 50 cents!

More in-depth debt measurement

Looking at a more complex rule where there are too many methods for a given type, the rule gets a little more complex and took some head scratching until it finally sunk in. If you look at the following query, you’ll see that debt is being calculated linearly. In this example, a class with 20 methods will incur 1 hour of debt and as we approach 200 methods, the debt increases to 10 hours (line 28).

For 20 methods it would take a hour. Because our class contains 23 methods which is over our limit of 20, then the debt calculated is 1 hour and 9 minutes.

To make this a little clearer, the graph below has the X axis representing the range 1 to 10 hours and the Y axis represents the number of methods. As the number of methods increase, the debt increases. This might seem obvious to you but I thought a graph would illustrate the point a little better.

Cost of refactoring this code? $57.50.

What about Annual Interest?

Annual interest is calculated like any other interest in the real world. If you don’t address the issues they get worse over time.

But hang on a second, isn’t problematic code static? And if so, how does it accrue interest?

Take the example above where there’s a problematic class with too many methods. If the problem isn’t fixed, chances are that developers will keep adding methods to that class. The larger the class becomes the harder it is to break out this functionality into separate classes. Assuming you want to follow the Single Responsibility Principle and move methods which perform similar actions together, this will be harder to do over time. On top of this the code surrounding and within these methods changes over time, not to mention calls between methods within the same class. So code is not static at all. This is where annual interest comes in and once again, it’s configurable and defined by what it means to your team.

Annual interest is calculated depending on a pre-determined threshold which in-turn, gives you a severity.  Annual interest and severity represent the same concept and can be configured in the NDepend settings.

With the defaults in place, an issue considered minor will accrue two minutes of annual interest a year and a blocker would take 10 man hours.

Using our last example and these thresholds, we can again, use the Linear() function to calculate the annual interest and corresponding severity.

Which works out to almost 4 minutes of annual interest, making the severity for this issue minor.

Configuration

Just quickly, all of the settings relating to technical debt estimation can be found in project properties and it’s where you can add things in like the hourly rate for a developer, hours in a work day, etc…

Summing up

My review of the new features in NDepend is far from over, but I thought I’d conclude the post and talk about some other features in following posts.

It’s great that technical debt and annual interested (the payback over the life of your code base) is now baked into all rules in NDepend. What a great way to spread the importance of this concept even further. When you’re talking dollars and cents you’ll almost certainly get the attention of your manager and developers, hopefully, will get the time they deserve to fix the important issues.