Get started with NDepend: Uncle Bob and the Zone of Pain

In this article, I want to show you how to get started with NDepend and use its features. Over what might be a series of several articles, we will explore how to set up the project/the solution and gain knowledge about the various types of reports tools like NDepend can generate for you and how you can benefit from them.

NDepend (or similar tools) have been a constant topic in the team I have worked in during the past years. People can have very different opinions on static analysis tools that generate code metrics, and graphical reports. Business people suddenly have the ability to “judge” code bases and code base architectures and to start finger-pointing if anything is amiss. Developers might fear this situation of being judged, of having to justify certain decisions to people misinterpreting or over-simplifying reports. On the other hand, you can also gain many insights from such an analysis. But let’s not get ahead of ourselves…

Trying not to be judgemental about a tool just being a tool, I will first show you how to install NDepend for the first time. Afterward, we will explore one or two features and I will also try to give some background information on selected topics (let us not forget that catchy post title). So, here we go.

Disclaimer

A little disclaimer at the beginning: I am fortunate enough to be provided with an NDepend license by the guys at NDepend. Since it can be a little pricy, you might not have this opportunity. But maybe it is an option at the company you are working with, or you are interested enough to check out the 14-day-trial on the NDepend website. Whatever the case might be, I will be very honest about this tool, if necessary, even though I am getting to try its Pro features for free.

First-time setup

  1. Obviously, the first step is to download the necessary files from NDepend’s website. For starting the free trial, you will have to register an account. If you are lucky and already have a subscription kee, you can directly download the necessary files from there as well.
  2. The download consists of a zip file containing all the necessary executables already, so simply unzip it to a place of your liking, but not in any %Program Files% directory.
  1. From there, if you do have a license, open a PowerShell window and run ./NDepend.Console.exe --RegLic REPLACEME. If not, just skip this step.
  2. One obvious way to use NDepend’s toolbox is from within MS VisualStudio. For that, execute the NDepend.VisualStudioExtension.Installer.exe, make sure VisualStudio is closed, and select the correct version on your machine.
  1. Once the VS Studio extension installer is done, you are pretty much set up and can get started.

Coming clean – opening a private code base

Time to show your cards. Once you open a solution of your choice in Visual Studio, select Extensions -> NDepend -> Attach New NDepend Project to Current VS Solution from the top menu. In the following dialog, NDepend will scan your solution for all existing projects/assemblies and try to locate the corresponding DLLs in the output directories.

In the screenshot above you can see that I actually ran into an issue here: All those filtered assemblies should not have been there, they are the actual business logic of that whole solution. See, following a practice of a previous development team, I used to prefix namespaces of all projects with a custom word, say, Mcb.Application.MyProject using a definition in the Directory.Build.props. While that does make navigating DLLs in the final output folder of an application easier, there is no other benefit in doing it. And, as it turns out, NDepend does not expect DLL names to differ from respective project names, hence the information message 48 assemblies are not resolved. In more recent projects, I don’t adhere to this anymore, so removing the prefix and rebuilding the complete solution was not a big deal here.

Edit: Due to this article the guys at NDepend fixed this issue in a recent version. As of today (2022/13/09), this is still beta, but please make sure to update to the latest version.

As you can see, NDepend now resolves almost all projects in the solution. Also, using the corresponding text box, you might want to exclude test assemblies or even external dependencies so that you can focus on the quality of your own code.

Once you hit the Analyze button, it will take a few seconds until you are automatically redirected to the generated HTML report page, from where you can navigate to a number of different metrics pages and visualizations of the results. NDepend will have created a folder NDependOut in your solutions root directory.

Making sense of the results

As I said, NDepend features a ton of analysis metrics and reports, the ability to compare baselines, i.e., snapshots at different stages of your projects, and so much more. Instead of rushing through all of them, I want to take a closer look at two selected features. 1) I want to look at some of the metrics on the main report page, and 2) we will have a look at the abstractness graph because visuals are a lot easier to grasp.

Application metrics

The main report page gives you a lot of numbers many of which are solely for informational purposes. Knowing that you have 26k lines of code is nice to know but of no further analytical input. When comparing those numbers at different moments in time can however give you insights into the rate at which your code base is growing. And that might be an interesting figure, especially when top-level managers are throwing more workforce into your project to reach deadlines. Together with the results of the quality gates summary, you are likely to have more leverage in ongoing discussions with management.

Since, here, I do not compare the results with a previous baseline, there is not much to be gained from these results. I can generally be quite content that there are no critical or blocker issues in my code base (which is related to this, by the way), and, looking at the critical rules violated, I will only see that there are a few very complex methods that need to be tackled. But these are issues in very small portions of the codebase. Based on these metrics, you need to be careful not to argue about architectural issues in your projects. Project executives will state otherwise and will try to pin you down on that stuff, once deadlines were missed or features not delivered, so be careful with these numbers. I am talking first-hand here…
By the way, if you want to know more about the rules that NDepend uses, have a look at their rules explorer.

Abstractness vs. Instability

Higher-order executives love diagrams to judge development teams and their work, and once a tool like NDepend is in play, they will also love the abstractness vs instability graph. But it will also give us developers valuable insights into our work, so let’s have a deeper look into that.

This is also where Uncle Bob comes into play. For those of you having read Clean Architecture, the plot will look familiar, but maybe you skipped on the mathematical stuff, so let us recap on that.

In an online article in 1994, Robert C. Martin attempted to define measurables in the domain of software engineering and software architecture by mathematically defining concepts for the terms abstractness (A) and instability (I).

The Stable Abstraction Principle states that “a component should be as abstract as stable” and is defined as

    \[ A = \frac{N_A}{N_C} = \frac{\rm{Number\ of\ abstract\ classes/interfaces}}{\rm{Number\ of\ classes}} \]

Note that component in this case can mean project/assembly, module, library, or whatever scope you might have in your preferred language. By this definition, the abstractness can range between 0 (only implementations) and 1 (only interfaces) for a given component.

Second, instability is defined as

    \[ I = \frac{C_e}{C_e + C_a} = \frac{\rm{Number\ of\ outgoing\ dependencies}}{\rm{Number\ of\ outgoing\ +\ incoming\ dependencies}} \]

Again, instability can range from 0 to 1, so let us consider the edge cases here, in order to understand this metric. A value of 0 would mean that there are no outgoing dependencies, i.e., this component references nothing, while there are many incoming dependencies, i.e., many components are referencing this component. In this case, you are not very likely to change this component, thus making it a very stable part of your code.

Conversely, a value of 1 indicates that your component references a lot of other components, while at the same time no other component is referencing it. Such a component is deemed very unstable because changing it will have not any impact on other components – it could even be deleted without causing trouble.

Since I, personally, find the terms abstractness and instability sometimes hard to interpret when looking at the above scatterplot, let us add more descriptive terms for it.

As you can see, I have also added descriptions of what might be inside of these zones already, so let’s discuss the four corners of this plot:

(0,0) – The Zone of Pain

Uncle Bob neatly described this area as the Zone of Pain, hinting at the issue, that once you’ll have to change anything in one of these components, you’ll probably have to change everything else as well, since there are so many incoming references. But is that always bad? You will usually find model-carrying components in this area, i.e., DTOs, database schemas, and the like. If these classes are non-volatile (you are pretty sure what they look like) that is not a bad thing. If not, you are going to touch a lot of code with every change.

(0,1) – Contracts

In the upper left corner, you will usually find components containing contracts. Quite a few other components are referencing these, but there are almost no implementations to be found here. Changing any of these will still cause trouble, though.

(1,0) – Business logic implementations and executables

Here you will find components, that are relatively easy to change. They feature mostly outgoing references, are volatile, and are frequently used. Often, components carrying logic from the middle layer of your applications fall within this area. Also, you will find executable projects here.

(1,1) – The Zone of Usefulness

This one is easy. Either somebody forgot this code or wrote code thinking “I am pretty sure we will need this sometime”. No, you don’t. You are in the Zone of Uselessness. You can probably just delete this component or get rid of it in only a few steps.

This figure can actually give a lot of insights into the general health of your software architecture but as always, you will have to tread carefully when interpreting the result. In general, you want the big part of your components along the main (green) axis. But as I said, not every component near the Zone of Pain is bad per see. Some components need to be stable in your system. And some need to be volatile in case business requirements change. And, returning to the discussions you might have with executives or non-technical personnel, that is something to keep in mind when engaging in these discussions.

For the solution analyzed here, I learned that the dependency balance visualized by this graph is actually pretty satisfying. The one component in the Zone of Pain is indeed the library containing only the business entities (and yes, I felt the pain). Other than that, most of the components lie well along the main axis.

Before we conclude, let’s go for a quick fun part. What is more interesting than judging your own work? Correct, judging the work of others. Microsoft has turned much of its work into open-source communities. This is also true for PowerToys, so let’s have a look at the analysis of that codebase.

Application Metrics in Microsoft.PowerToys

Now, Microsoft, that’s actually not too bad. While the overall Debt rating is only a B (whatever that means. We did not talk about this, so please be careful to judge here), the scatter plot looks pretty good. It is interesting to note that there are quite a few projects that lie precisely on the extreme values, i.e., either featuring no interfaces or abstract classes or having only outgoing references, such as executable projects.

Conclusion

That’s it for now. We learned how to get started using NDepend in Visual Studio, and had a look at some of the metrics and the abstractness and instability graph in detail.

I hope you find the topic as interesting as I do, maybe you’ll even head over to NDepend’s website and start a trial, or you can transfer the knowledge you gained to your codebases or to the work at your job. That being said, NDepend offers a whole lot of other features. I will make sure to give you a follow-up article on other selected topics as well. Let me know in the comments if you’d like to see any specific feature.

Please leave a comment, share on social media, and subscribe to our post newsletter!

Leave a Reply

Your email address will not be published.