NDepend Review: A great tool to expose the technical debt in your projects

NDepend Review: A great tool to expose the technical debt in your projects

I was sent a license to test NDepend and now I am going to give my impressions

Some weeks ago, I was contacted by a representant from NDepend to check their product out. Long story short, the tool is amazing! But let me give you more details.

What is it

NDepend is a Visual Studio extension that helps you to know the amount of technical debt is being produced in the code. I am not talking about legacy code or old technologies here. I am specifically talking about code that needs to be refactored at some point.

A simple example is an enormous method that was created and, for sure, you will need to break it into smaller methods. NDepend will catch that and flag it as technical debt so you can fix it before it becomes a code smell.

How install and to use it

They have a YouTube channel with short videos to guide you, aside from an extensive documentation that will help you to walk through the tool.

Using it in my projects

After I got it installed and going through some of the documentation and tutorials, I decided to give a first try with the source code of my own website, which is available on GitHub. It turns out that I got rating A, which means that it’s quite alright and it doesn’t seem to have so much technical debt.

Then I tried another one, also available on GitHub, which I used to write this article about the Datatables component. As the rating was B I saw this as an opportunity to improve it.

As I went through some rule and started fixing some issues, I noticed that the debt was increasing, instead of decreasing.

It turns out that my changes were affecting the code more than I expected as they were breaking changes. I mean, transforming an instantiable class into static is kind of a big deal. From all the changes I made – which solved some problems – this was the one that caught me of guard. Mostly because we do this all the time being sure that we are not breaking anything, but we are.

On a brighter note, I had this method which NDepend claimed to be complicated:

public static void Order(ref IEnumerable<PersonTableViewModel> items, int orderColumn, string orderDirection)
{
    switch (orderColumn)
    {
        case 0:
            items = orderDirection == "asc" ? items.OrderBy(o => o.FullName) : items.OrderByDescending(o => o.FullName);
            break;
        case 1:
            items = orderDirection == "asc" ? items.OrderBy(o => o.PreferredName) : items.OrderByDescending(o => o.PreferredName);
            break;
        case 2:
            items = orderDirection == "asc" ? items.OrderBy(o => o.Phone) : items.OrderByDescending(o => o.Phone);
            break;
        case 3:
            items = orderDirection == "asc" ? items.OrderBy(o => o.Email) : items.OrderByDescending(o => o.Email);
            break;
        case 4:
            items = orderDirection == "asc" ? items.OrderBy(o => o.Age) : items.OrderByDescending(o => o.Age);
            break;
        case 5:
            items = orderDirection == "asc" ? items.OrderBy(o => o.Status) : items.OrderByDescending(o => o.Status);
            break;
        default:
            items = items.OrderBy(o => o.FullName);
            break;
    }
}

I made a small refactoring, trying to abstract away its logic and now it looks like this:

public static void Order(ref IEnumerable<PersonTableViewModel> items, int orderColumn, string orderDirection)
{
    switch (orderColumn)
    {
        case 0:
            items = ApplyOrder(items, o => o.FullName, orderDirection);
            break;
        case 1:
            items = ApplyOrder(items, o => o.PreferredName, orderDirection);
            break;
        case 2:
            items = ApplyOrder(items, o => o.Phone, orderDirection);
            break;
        case 3:
            items = ApplyOrder(items, o => o.Email, orderDirection);
            break;
        case 4:
            items = ApplyOrder(items, o => o.Age, orderDirection);
            break;
        case 5:
            items = ApplyOrder(items, o => o.Status, orderDirection);
            break;
        default:
            items = items.OrderBy(o => o.FullName);
            break;
    }
}

private static IEnumerable<PersonTableViewModel> ApplyOrder(IEnumerable<PersonTableViewModel> items, Func<PersonTableViewModel, string> orderBy, string orderDirection)
{
    items = orderDirection == "asc" ? items.OrderBy(orderBy) : items.OrderByDescending(orderBy);
    return items;
}

Boom! The dashboard is saying that the technical debt decreased. I am sure that if I insist I can decrease it even more.

Performance

Let me be honest: I like to keep my IDE simple and fast, which means that anything that degrade its performance will not be installed. Yeah, I know, I recently built my new computer. But it’s an old habit which may be difficult to overcome. So, I was concerned that I wouldn’t be able to even open my VS after installing NDepend but, for my amusement, NDepend is very fast.

The tool is not intrusive, and you barely notice unless you trigger it on the menu (Extensions > NDepend) or in the red circle in the bottom right. Alternatively, you can have its windows stacked on your Visual Studio.

Miscellaneous

I couldn’t check some things because of how my projects are built, but I will talk about them.

Code coverage

My projects don’t have unit tests. Yeah, I know, they should. But I will work on that. The thing is that NDepend allows you to import your code coverage data into the dashboard and see how you are doing. This should increase your issues since NDepend will start warning you about the methods which are not being tested.

Rules

You can – and perhaps you should – edit the rules NDepend uses to assess your code. The rules they use are general, but it’s well known that each team or company will have their own code standards.

Conclusion

I like NDepend and I am going to use with everything I can. It’s nice to have a tool which groups all useful information in a single dashboard. There is still a lot to learn and use, but I think I am in a good path. Unfortunately, I didn’t have a big enough project in my computer to fully test it. Not to mention that some things would need much more time to use such as trending charts. Also, I’d love to see how NDepend would behave when coding with more people.

Bu the most important is: The more I use, more my code will improve. 🤓