Let me start this article with mentioning that I had exactly the same sentiments as Henry Cordes in 2009. I was also approached by C# MVP Patrick Smacchia to look at the tool NDepend he developed, and after a quick search on Google I got really excited to check it out! Because, next to the fact that I was also honoured he considered me, I was also really curious about what NDepend could do for me.
NDepend in a nutshell:
Quality of software is something software engineers can debate forever. There is functional quality of software, which is about the fit for purpose of the software. Often measured by acceptance testing and such practices. Then there is the quality of the static structure, which concerns aspects such as robustness, maintainability, and so forth. One of the ways we can measure this is by analysing the code. And this is exactly where NDepend offers superior support, which will be the focus of this article.
So how does NDepend help you analysing your code and thus help you improve the quality? NDepend does this by providing a lot of features! In order to check them out I downloaded and installed NDepend as explained here for instance (NDepend has nice documentation also but I found that blog post to be very helpful). I used the Visual Studio integration, because I like having my development software at one place. I opened one of our old tools which needed some work done and has become a WinForms legacy application. I wanted to see if NDepend can help me whip the application in shape again. I’ll take you with me on this small journey and braze over some of the features to see what NDepend is about.
The first thing you’ll want to do in order to use NDepend is “Attach new NDepend project to VS solution”:
This will allow you to choose which assemblies you want analysed in the next dialog. There is very good support on NDepend’s website, so I won’t include every screenshot. But you’ll usually want to start with the dashboard, which in my case looked like the following screenshot:
You also have the option to let NDepend make a report in HTML, which looks like the following screenshot:
When you see this for the first time it can be quite a daunting task to take in all the metrics. Of course not with such a small application as the one I’m using for this article. But I’ve also let loose NDepend on one of our bigger applications and then the numbers attack you at first. Which ones do you care about? I have my own ideas about code comments, so I’m not really bothered with comment coverage, for instance. But my interest was immediately piqued by the rule violations. But what are those rules about then? And are there rules I care more about than others? Questions you need to figure out with your development team when you talk about the quality of your code, make up the code standards and see how you can fit in NDepend to guard these for you.
In order to answer these questions now for this blog post, I’ll look at some of the metrics NDepend can dig up for you.
You can go scientific about code metrics and perhaps have this placemat to enjoy your lunch on, but for the clarity of this article let’s just pick a few metrics of the 82 NDepend provides and judge them on face value.
This metric is basically about the number of decisions in a procedure (think ‘if’ statements). Both Visual Studio and NDepend provide this code metric, but NDepend takes this a step further by also providing the IL cyclomatic complexity which is language independent. NDepend recommends (in short) for the CC no higher than 30 and for the ILCC no higher than 40. While Microsoft will report a violation if it’s higher than 25. With NDepend if I want to adjust the thresholds I can simply adjust the rule which is constructed with NDepend’s “CQLinq” which I’ll get back to in a moment. In Visual Studio you can only customize rulesets not independent rules (see discussion on Stack Overflow here).
Depth of Inheritance Tree
The DIT is a metric which indicated the number of base classes a class inherits from. This metric could say something, or could say nothing at all. What I mean by that is that sometimes when you inherit from a class in the .NET framework for instance, or a third party library, this metric could be high. But inheriting from base classes from a framework is often not a concern for maintainability. But if you make complex inheritance like this in your own code base (and your application is not a framework) then maintaining the code base can become challenging over time and it’s widely accepted to consider Composition via Dependency Injection. NDepend recommends no higher than 6 for this metric, I’d personally say keep it equal or lower than 3 as a rules of thumb.
Immutability & Purity assertion
This is not a metric per se, but actually a set of dedicated CQLinq (more about this in the next paragraph) conditions and rules, which assert immutability and purity on your classes and methods. Environments become increasingly multi-threaded, where immutable objects (state doesn’t change) and pure methods (execution doesn’t change field states) are necessary for controlling potentially negative side-effects. To highlight one metric, I’ve chosen for this article to grab a relatively simple rule, called: “Fields should be marked as ReadOnly when possible”. Fields that are only assigned by the constructors of their class are marked as potentially immutable by NDepend, asserted by the IsImmutable metric. If these potentially immutable fields are not marked as ReadOnly, then this rule will cause a warning. And there are eleven rules filled with metrics like this one to assert the immutability and purity of your code base.
Code Query LINQ is in my humble opinion one of NDepend’s major selling points. It’s a language based on .NET C#’s LINQ which lets you query your code base. Give or take 200 default queries and rules are provided with each new NDepend project, which you can adapt if need be. The CQLinq editor is just as much a pleasure to work with as the normal code editor from Visual Studio as it provides code completion and intellisense. It provides adequately descriptive information in cases where compile errors occur. And last but not least the documentation is integrated via the tooltip, which is actually pretty handy!
So for instance if I take the rule: “Avoid making complex methods even more complex (Source CC)” which uses the aforementioned Cyclomatic Complexity we can see that the rule is violated at 6:
We can easily change this to 5 for instance if we want the rule to be more restrictive. It is really worth spending time constructing or altering rules to see what you can get out of CQLinq and construct your own sets to comply with your Definition of Done.
About 50 trend metrics are available per default and more to make with CQLinq. Some trend charts are on the dashboard per default, but they can be made yourself and put on the dashboard. One such trend chart is the default “Max” trend chart, which keeps track of the maximum values of four metrics:
I could for instance deduct from the blue line that the maximum lines of code for a method has slightly increased, making a method even larger. I should really get this number down by refactoring, to decrease the complexity of the code and increase maintainability. Well, the idea of trends is fairly straightforward and clearly explained on NDepend’s website.
To obtain an overview of the coupling in your code base NDepend provides a Dependency Graph, which I generated for the subject application of this article:
Remember that we are after “high cohesion” and “low coupling”. Concerning the low coupling I can see in this graph that the coupling only occurs on framework related components, so this is not really something to be alarmed about. As for the high cohesion I can see that the entire application has been stuffed into one big “god class” (see: Sod.Notificare.NumberVerifier). And this is something to investigate further. Because elements with low cohesion bundled up in the same component can cause maintenance headaches. You can hold your mouse on the component you want more information about:
Again providing you everything you need to start improving the quality of your code base. It is obvious this component is going to be refactored into smaller components, improving the cohesion and thus improving maintainability.
You can also view Dependency Cycles in a matrix.
NDepend doesn’t analyse coverage itself, but instead relies on coverage data you can import from a variety of technologies.
I added unit tests to the legacy application I used for this article and analysed the code coverage with NCover. Then I imported the code coverage data in NDepend as described by their documentation. The concerning section on the dashboard now shows:
You will get some additional information from the Change Risk Analyser and Predictor (C.R.A.P.) method code metric, which only executes when some code coverage data is imported from code coverage files:
Which tells me I have some work to do if I want to get the coverage up and the CRAP score down (because the lower this metric is the better it’ll be for maintainability).
NDepend spits out a couple of diagrams to show various forms of complexity on your code base. The trend charts, dependencies matrix, dependencies graph have been covered in other paragraphs. NDepend can also generate a Treemap metric (read: Heat map/Code metric view) and the Abstractness vs. Instability diagram.
It allows you to specify on what depth (read: Level) you want to analyse the code, which in the above figure is on: “Method”. It allows you to specify which metric you’d like to use for the relative size of the blocks, which in this case is set on: “Lines of code”. And last but not least, which metric is used to determine the colour of the block, which is set on (again): “Cyclomatic Complexity”.
But there’s a reason the metric CC pops up again, because it’s a very useful one. The above chart allowed me to immediately zoom in on the single yellow block that really jumps out and when you hold your cursor over it, it’ll show why:
As you can depict from the information shown in the screen this block is relatively big and has a relatively high CC, which makes it an excellent candidate to start refactoring first. After that I’ll tackle the largest green block on the left and try to refactor it. And this is where the treemap excels for me. If I have a legacy application I need to start maintaining and I want to clean up the code, I’ll definitely fire up this diagram first.
Abstractness vs. Instability diagram:
To put it short (and cut some serious corners) this graph combines two metrics. Abstractness, which basically represents how much the code base depends on abstract classes, interfaces and such so it can cope with changes easier and is very flexible. And Instability, which is about how much the code base is coupled with concrete implementations, making it more inflexible. And when you have extremes in one of these metrics you’ll either hit the “Zone of Pain” or the “Zone of Uselessness”.
This graph is all about balance and the larger your system is, the more important this becomes. In this particular case I got out of this graph that I’ll be changing the application severely with every request that comes in. Which can be a choice. To abstract this application and make it more stable is not worth the return of investment and we’ve chosen to occasionally have more work to do, because the frequency is pretty low.
You are probably wondering how NDepend stacks up against tools you have probably already worked with. I know I was! I am mostly familiar with ReSharper and my instinct was to compare NDepend with this tool.
If NDepend is the Swiss army knife, then Reharper is like a scalpel. In fact, it is actually not appropriate to compare the two tools at all if you dig into it. Remember in this article that I’ve said on several occasions that the conclusion after observing some metric or validating a rule was often to refactor or improve in some other way the code base. So while these analyses across the entire code base were done with NDepend, Resharper really comes in to help me out with the actual groundwork of refactoring, renaming and popping up with handy advice how to improve the code even further almost on a ‘line of code’ level. This is an area that NDepend does not touch, and Resharper will not be able to provide so much information across your entire code base. In other words, as has been perfectly laid out by this article, they complement each other! Use Resharper in your day to day work to boost your productivity and then have NDepend tell you something about the quality of your code with every build. More on this can be read from mister NDepend himself.
When I go out camping, I’ll always want my Swiss army knife with me. And now when I go out developing software, I know I’ll always want NDepend with me! The static code analysis capabilities of Visual Studio itself, FxCop, StyleCop all have their uses, but are not at the level that NDepend offers (see a great discussion about FxCop and StyleCop here). I am starting to sound like some commercial, but that’s not all! You can compare code bases between builds. You can integrate NDepend in your build process, which could be as simple as executing the NDepend Console and catching the exit code. If you want to extend your Swiss army knife you can have a look at NDepend’s API. With NDepend’s API it is easy to develop your own analysis tools based on NDepend’s CQLinq and NDepend.PowerTools. You’ll be able to programmatically do almost anything NDepend does. You can read more about it here.
I have a small concern though. If you are really going to put yourself in the market as the Swiss army knife, then go all the way and provide code coverage data yourself, instead of relying on other tools. I was personally bummed out by having to buy yet another tool like NCover, or upgrade my MSDN subscription, when NDepend isn’t free either.
Having said that, code coverage data is something NDepend doesn’t want to compete on while it has so many other things to offer. Coverage tools are extremely technical and very specific. NCover, dotCover and VS all do a great job. Plus nobody else complained about this actually and users are in general asking to support other tools like NCrunch. In fact, it is the only thing I could come up with to be able to write down a con. In other words, if you care about the quality of your code, you need NDepend!