This is the third post in a series about using NDepend for code analysis. Below are the links to all posts of the series (will be updated as more posts are published):
- It NDepends! Part 1: Motivation and overview
- It NDepends! Part 2: Metrics and rules
- It NDepends! Part 3: New dependency graph in NDepend 2020.1
What’s new in NDepend 2020.1
As I shared in my previous posts, I consider NDepend to be an amazing static analysis tool (perhaps, even a framework), especially useful for visualizing code structure of big .NET solutions. Earlier this year, a new updated version was released and I was lucky enough to get a change to play around with it and see the new features for myself.
Perhaps, the main change in this version is a completely rebuilt dependency graph. As a user, you will feel this in a snappy UI and navigation system, which scales very well and easily handles solutions with 100+ projects. Looking at Orchard Core as a relatively big example of a .NET project (156 projects in the solution), it’s not immediately clear how all these pieces fit together, what are the logical groups, and who is using whom. Just look a the screenshot of Solution Explorer:
However, if I install NDepend extension into Visual Studio and run the analysis on that solution, I immediately get a very different view on this:
First interesting feature that grabs my attention is the automatic grouping. There are five distinct clusters of projects on the graph, which combine nodes based on assemblies or namespaces/types. Personally, I think this is an amazing feature, which presents a real map of the solution and makes it possible to navigate even an unfamiliar codebase. It is crucial to understand how this clusterting is applied, so here’s a quote from the documentation:
Two cluster level are proposed:
- Cluster Complex Assembly Set: When set, this applies when there is more than 20 assemblies to show. An heuristic appends cluster nodes that are grapes of assemblies to simplify the assembly graph. If referenced assemblies like ASP.NET Core assemblies are shown on a graph, they get their own clusters.
- Cluster Complex Element Set: When set, this applies to all sub-graphs made of namespaces, types or methods and fields, that contain more than 20 elements. Thanks to cluster nodes added such sub-graph gets simplified.
My understanding of this is that NDepend will try to define groups based, on the one hand, on the total number of assemblies (human brain has limits) and, on the other hand, on the direction of dependency edges. It only makes sense that an arrow connecting two clusters represents the somewhat aggregated “depends on” relation between the corresponding assemblies inside those clusters. This is, in my opinion, very natural and helps to avoid being overwhelmed by the actual dependency graph (with all nodes/edges and without any grouping):
Yeah, good luck making sense of that!
If I want to zoom in on a specific assembly in the graph, this also works very intuitively just by scrolling the mouse wheel. And then double-clicking the project of choice will show only its callers (green, on the left) and callees (blue, on the right), filtering out the noise of all the other nodes.
Other notable features:
- the dependency graph is searchable, i.e. you can enter the type name in the search box and immediately zoom in on it
- depending on the selected mode, the nodes and edges can represent a call graph, a class inheritance graph, a coupling graph, a changes map (new elements added since the previous baseline), and also a path or a cycle graphs.
With this amount of flexibility and different graph modes, NDepend successfully manages to reduce cognitive load when showing a large .NET solution and will keep a curious software engineer busy for a long time exploring all the hidden dependencies. I, for one, really enjoyed the combination of macro- and micro-perspectives, as well as smooth transitions between the two. It’s great to see NDepend tooling evolve and mature with every year, so I’m curious what the next versions will bring.