In my old company we used NDepend quite extensively on our build servers for a multitude of reasons so let's check out what is the current state. For this blog post I used version 2022.1.4.
Also note that I got a license to test NDepend free of charge to gather that exact feedback you will read in a minute. This had no influence on what I wrote.
What is NDepend?
NDepend is a static code analysis tool like StyleCop. It runs through your code and assemblies and checks for certain problems. And now here comes the twist: You define exactly what a problem is. How? That I will show you in a second. On top it comes with a lot of pre-defined rules grouped in different categories and severities. The ultimate goal is to notify you if NDepend encounters code smells in your software. The sooner you fix it, the better for your maintainability. You get bonus points if you integrate such things as quality gate into your CI-Pipeline. NDepend can be setup in multiple ways. I will not annoy you with a "Get started" tutorial, because this you can read on the official page. There is a Visual Studio plugin, standalone application and of course ways to integrate it into your automatic build pipeline. I will have a closer look into the standalone application. The reason is simple: I am mainly a Rider. I also know lots of folks using VS Code. As the base for my examples I use my own ValueStringBuilder-Library.
If you have followed the getting started guide. You can directly jump in.
The first steps
The first thing you would do is to create a new project. If you start the standalone application you can create a new project via
File > New Project. I would suggest, put it directly to your code. It should get versioned as all of your code. Then you can scan assemblies, load projects or solution files. If you want to manage your whole solution, go for that option.
After that, you can either press F5 (like building in VS) or press that green triangle to run the analyzer. Once it is done you will get presented a dashboard.
Now this dashboard doesn't seem like much, but boy there is many things. I will go through them one by one, but I want to show you the possibilities upfront:
- On the top you can see the current version and baseline version. That means we have stuff which let us compare between different versions of our code. That is crucial for example if you want to detect breaking changes in your API, which by the way is supported by NDepend.
- It shows you rules, Quality gates and issues. More to that in a minute.
- It shows you a technical debt rating, even with a rough estimate how long it takes for you to get rid of that debt.
The technical debt part is basically an assessment based on your rules you have activated. The rule part we will cover in a second, promised 😉. You can also click on the technical debt part and on the left you have a detailed tree-view showing you how the debt was calculated (how much every single rule played into the whole construct).
You can also look at your dependency graph or matrix or go through pre-defined metrics like (Cyclomatic Complexity) for every single component. The visualisation gives you a nice overview over what is going on in your code. Now let's come to the heart of NDepend: The rules!
Rules and code issues
On the lower part you have the possibility to see all the rules. They are grouped into categories. Each category consists out of dozens of rules itself. You can click on them like seen in the picture below:
On first glance we can see some types in a small tree view. Those are the types violating that specific rule I selected. If you have the plugin for Visual Studio and click on the function, you directly get redirected to that source file in Visual Studio.
But more important is the top. We can see the definition of the rule file itself. And guess what? It is our old friend: A LINQ query. That's right, all the rules are written in LINQtechnically CQLINQ. That gives you incredible power to either write your own rules or adapt rules with the same language you wrote your production code.
Therefore NDepend brings a lot of extensibility with it. Remember how I said earlier, we can compare different version of the code to deduct if we have breaking changes? Also that is purely done in LINQ:
warnif count > 0 from m in codeBase.OlderVersion().Application.Methods where m.IsPubliclyVisible && (( m.WasRemoved() %% !m.ParentType.WasRemoved() && !m.IsObsolete()) // left out for bravery ...
As you can see NDepend brings a lot of extra utility so you can use LINQ to create rules. You can also adjust the rules to your needs. 200 Lines of code for a method is way too long? Reduce it to 50! The joy begins when you create your own rules:
You can create new rules inside in any off the categorize (or non at all). I explicitly say "rule" instead of violation, because you can also create reporting in that way. More to that later. So let us create a small rule, which triggers when the Cyclomatic complexity is too high. The cool thing is that NDepend has its own intellisense including a very good documentation of all the objects you get offered:
At the beginning you have to take some time to get into the new API. There is a lot to discover. As a base I would always suggest take on of the pre-defined rules and adapt it.
warnif count > 0 from m in JustMyCode.Methods where m.CyclomaticComplexity > 5 select m
Even though it is funny to create your own rules, I don't think this will often happen. As I said there are so many pre-defined rules, that I am more convinced that you will adopt some of them rather than creating them from scratch. More likely is that you create your own small reports. Reports are just informational tool, which are not meant for indicating a problem. NDepend brings some off them with it. For example you can create a summary for the test coverage off each of your assemblies, or you can cluster them together to "business" units and have the coverage there.
Visual Studio integration
The neat thing is that you have a lot of the features and dashboards also directly integrated into Visual Studio itself. You can use it either on the fly or just import your newly created projects with all your custom rules:
Once it's loaded you can go directly to your dashboard to have a better overview:
Another feature is that you can easily create a report. NDepend can export all of the results as HTML. That means on every built you could export the result and always have an eye on the current state on the project. You can also share those artefacts to anyone if you wish. They just need a browser.
Here is how one could look like:
What could be improved
There are some things. Let's start with the unreasonable one 😄: It would be perfect to have feedback sooner. Kind of what
SonarAnalyzers do. You get direct feedback in the source code while you type. I say unreasonable, because I know that this is just not possible. First we would need massive performance to have it roughly "realtime" (even though on save would be also nice) and second sometimes the software can't just not pin down the problem to one entity in every case.
The technincal debt estimation feature is in fact very cool. Just don't take it to exactly and always check if the tradeoff is worth it. You might take it to tell someone (normally business) that you need to refactor something. You can clearly show outcome. We all know more or less what technical debt is, so that can help us.
The other issue I encountered is, that the GitHub Action is currently under development and may hit with the upcoming 2022.2 release. That would really close a gap. Lots of people (like me) are on GitHub. Not only open source people but also a lot of companies using GitHub including GitHub-Actions.
Also I am looking forward for the upcoming version which runs on .net 6.0. That enables NDepend to run on arm64. That is interesting because this is the architecture of a MacBook M1. Lot of folks (including me) are using this device. A small hint: You can't check the preview version of .net (currently .net7.0-rc1) with NDepend at the moment. We have to wait for an upcoming release.
NDepend is a very helpful supplement for your project. It is not a replacement for Roslyn analyzers. But both together can give you good tools to control and monitor your code quality. It is meant for teams to always have an overview over what is going on and when you have to correct course. For smaller projects it can be an overkill depending on your needs. In the end you can always try it for free for 14 days.
Update 26/09/2022 - It works on Mac M1
The upcoming version 2022.2 is running on .net 6 which also allows it to run locally on a MacBook M1 or M2. That is great news! There is a guide setting you up on the official website. Until now VisualNDepend is only working on Windows, so you have to leverage the CLI to make it run. As I am anyway someone loving the CLI (due to CI/CD reasons, where you have no UI anyway) here a short description. Switch to your NDepend folder in the console.
To create a new project you can run:
dotnet net6.0/NDepend.Console.MultiOS.dll -cp /path/to/your/file.ndproj /path/to/your/solution.sln
All the magic happens in this assembly under
net6.0/NDepend.Console.MultiOS.dll. The first argument is the ndproj file the tool will create and the second one is the solution file you want to link to that project (of course you can also take a single csproj if you wish). That is no different to the VS plugin or VisualNDepend.
Afterwards you can run the analysis via:
dotnet net6.0/NDepend.Console.MultiOS.dll /path/to/your/file.ndproj
This will print out all the relevant information and violated quality gates. It will return a non-zero exit code if there is one rule violated. Bonus: It will create an HTML report automatically. All in all very welcome changes! Keep it going!