Using NDepend to Help Improve Architecture

Or, "how a static analysis tool can help you write better apps"

Long time, no see! I've been busy these past few months after having jumped right into self-employment and software consulting, and obviously have let this blog slide a little. But worry not: exciting things are ahead, starting right now!

A couple weeks ago, I received an email from Patrick Smacchia of NDepend, asking if I would like to give their product a try. In case you're not familiar with it, NDepend is a static analysis tool for .NET. I had used a trial at a previous job a couple major versions ago and found it immediately useful, so I jumped at the chance. I'm also a big fan and daily user of ReSharper, so I was interested to be able to compare and contrast these tools.

Setup

Right off the bat, I was happy to see how quick I was able to get up and running. The installer is small, at least by today's standards, and took less than a second to download on my mid-budget broadband connection. Installation into Visual Studio 2015 Community went swimmingly, and even though I fumbled around for a bit since I didn't RTFM for how to activate my license, I was still looking at my first analysis report in under 5 minutes from start to finish. Wow!

Analyses, Metrics, and Trends (Oh, My!)

Upon completing its analysis, NDepend shows a dashboard of stats, along with some trend graphs, which I'll talk about later.

NDepend Dashboard

As you can see in the "Code Rules" section, I've got some violations. Nothing critical (because I already fixed those so I wouldn't embarrass myself!) but if we click on that blue link, we get a list of things NDepend thinks we could do better.

NDepend Violations

Clicking on any of these violations will bring up a list of where the specific offenses occur, which in turn can bring you directly to the code in question.

When I took a look at the violations of one of my client applications (sorry, extensive NDA = no juicy details) it matched most of what I had mapped in my head (and on our Trello board) as needing improvement, but it was good to have a second opinion confirm my suspicions, and reassuring to see my gut-feelings affirmed!

I quickly got the feeling that while ReSharper is more about the here and now of head-down refactoring – at least how I use it – NDepend is giving more information on the overall health of the code. More than once I found myself using NDepend to find something that needed work, and then using ReSharper to do the actual refactoring. Rebuild, run tests, and see the warning disappear. It's like a TDD cycle for code quality, and it was more fulfilling than I expected!

Getting back up to the overview-level of things, I really like the "Dependency Graph" feature, as it gives a good immediate overview if you're just jumping into the codebase. Here are the namespace dependencies for this site:

NDepend Dependency Graph

Small and straightforward, as a microservice like this should be!

Pull up something more complex, though, like this larger project's (redacted) assembly dependencies, and it's easy to start to see potential architecture improvements.

NDepend Dependency Graph

There are some nodes (assemblies) – mostly in the second column – that are referenced by the same assemblies and reference the same assemblies...these could probably be combined, while still maintaining namespace separation, which could in turn increase performance and decrease complexity. NDepend has some good white books on this and similar topics.

Similarly, at the overview level, but also with the ability to quickly dig into problem areas, the "Metrics" view allows you to see, in graphical form, what your application looks like from various code quality perspectives.

NDepend Metrics

The above is this site, with the size of the squares representing lines of code, and the color showing their cyclomatic complexity. You can see a couple of the methods are a lighter shade of green (on their way to yellow: bad, and then red: really bad) which is a warning that they're starting to do too much and should probably be broken down.

On a much larger, more complex "legacy" project, the metrics graph will look more along the lines of something like this:

NDepend Metrics

Hovering over a square will tell you the class and method name, and you can double-click it to go right there and fix it up! You can also highlight the top X issues for any given metric. You can probably tell which assemblies I've already thrown my hat in the refactoring ring at!

Since NDepend keeps track of analysis results over time, it also has the ability to show how certain metrics are trending over time. For example, I can easily see that overall cyclomatic complexity has improved 14%, or that test coverage has increased 734%, or that we've fixed more than 100 critical violations since I started working with the team. These are all actual numbers, and it's great to have some hard facts like this to back up those feelings that things are headed in the right direction!

.NET Core

Since this site is running on .NET Core, there were some small workarounds required to be able to analyze this project, but I could still generate a report, view the recommendations, and improve the quality of my code quite easily. For anyone else looking to do this right now, the main thing is that, rather than attaching the NDepend project directly to the solution, you'll need to select the DLLs from the bin/Debug directories, which in turn means you'll need to compile (and update binaries) via the CLI (dotnet build) in order to get new analysis reports. Visual Studio appears to compile to a temp directory, or maybe even in-memory, so it may be possible to find where that is, and reference those instead, for an easier update process.

The two smaller .NET Core-specific issues I found were not being able to jump directly to static members via the violation lists, and certain framework requirements getting flagged as violations (e.g. it suggests classes implementing Controller should be made sealed or static, which means MVC doesn't pick them up as controllers) but these are in no way dealbreakers for me, I just needed to keep them in mind once I figured them out. Kind of like looking both ways before crossing the street, even if you have a walk signal.

Patrick also assured me that a new version of NDepend was coming very soon with improved .NET Core support, so I'm super excited about getting my hands on that (maybe even a dev build, wink wink nudge nudge) ASAP!

Conclusions

Overall, I'm really happy with my initial spin around the block with NDepend. I can see using it becoming part of my daily workflow, helping fight the good fight against a codebase's constant entropy. I think it's a great compliment to ReSharper, and a great addition to any developer's toolbelt. On the flip side, I'm not worried about it taking my job, because although it gives great insight into specific issues, it still takes a skilled developer (or dangerously powerful AI) to make the right decisions about the information provided. I'm glad to have it as part of my arsenal now, and expect that it will enable me to provide additional value to my clients.

Whether or not you've used NDepend, what kind of tips/tricks do you have for finding issues with your code and improving architecture and code quality? Sound off on Twitter using the "comment" link below!