Wednesday, December 25, 2013

NDepend: Static Analyzer, Metrics and Dependencies

When we get a new existing project for analyzing, development or support, we often have a question: where to start from? There might be a lot of legacy code, assemblies, projects, solutions, etc. There's something that can help us to get a clue: NDepend - a tool for managing complex .NET code.

Installation

NDepend can be downloaded from the official site www.ndepend.com. The response email contains installation and licence activation details and other necessary info to start.

The installation package consists of:

  1. NDepend Console - console application to run NDepend commands.
  2. Visual Studio Plugin installator. NDepend 4.1 supports Visual Studio 2008, 2010 and 2012.
  3. NDepend Power Tools with the source code. This is a set of short programs based on NDepend API, demonstrating its syntax and capabilities.
  4. Visual NDepend. This is a standalone Windows application that allows NDepend analysis outside of Visual Studio.
  5. Links to build process resources. It contains information about how to integrate NDepend to countinuous integration systems and build systems. It can be integrated to CruiseControl.NET, FinalBuilder, TeamCity and Team Foundation Server. It supports NAnt and MSBuild tasks.

Basic Features

NDepend project

There's a special NDepend project format, based on XML, with extension .ndproj. This file contains a set of assemblies to analyze, NDepend project properties and a special set of rules and queries to be applied to the project.

The NDepend project can be attached to existing Visual Studio project, solution or to a particular set of .NET assemblies permanently or temporarily. Permanently means that it puts the .ndproj file to the solution folder and includes it to the solution .sln file and places the NDependOut folder with reports and output. Temporarily means it puts the same into "C:\Users\...\AppData\Local\Temp\" folder, so your sources are not messed with NDepend files and your solution file remains in readonly mode. The first case is more suitable if your team decides to track you solution with NDepend permanently or continuously. The second case is more suitable if you decide to look into the project once or once in a while.

Dependency Graph

Dependency Graph allows to visualize dependencies between different project components and (if included by special option) third party components. Basically it can show dependencies between:

  1. assemblies;
  2. namespaces;
  3. types;
  4. method and fields.

Let's have a look on iTextSharp, an opensource library for PDF generation and manipulation:

The graph is interactive, if you hover mouse over a box, it highlights dependencies and metrics information. The size of a box is directly proportional to the number of lines of code, but it can also be adjusted to show the number of IL instructions, general cyclomatic complexity or any other selected metric.

If we right click on a box, we can choose an option "View internal dependency cycle on graph" and have a look on dependencies inside the selected box. In this case it will appropriately be namespaces:

But what we can see here, is that the graphs in the both examples above are practically useless. The assemblies dependencies in the first sample is too obvious, clear and straightforward to be visualized. We can just open the solution in Visual Studio and we will get the idea. On the other hand there are so many different color boxes and narrows on the second graph with namespaces, that it becomes more difficult to get a clue. It can be zoomed though to see a particular area of the graph, but imagine how it looks if there are even more boxes:

Not very valuable, is it?;) Thus practically there is some reasonable range of number of boxes where the Dependency Graph can be useful, between "it's too obvious" and "it's too complex". For more branched dependencies, the Dependency Matrix is designed.

Dependency Matrix

Dependency Matrix gives us more powerful opportunities for dependencies analysis. Suppose we need to see how the assembly System.Drawing is used by iTextSharp:

We can see that assembly System.Drawing is used by assembly itextsharp only, and 30 members are used. Now let's expand the assembly and see what actual types and namespaces are involved:

Here we can see that 3 members of the structure System.Drawing.Point are used in the .ReadAll() method of the class iTextSharp.text.pdf.codec.wmf.MetaDo (another usage is found in the constructor of iTextSharp.text.pdf.codec.wmf.MetaState class). And this dependency is not obvious and it's not so easy to extract and understand from the source code as the .ReadAll() method length is 568 lines!

It is very similar to the commonly used "Find Usages" feature of JetBrains ReSharper, but with much more opportunities for complex analysis.

Although the Dependency Matrix seems to be less intuitive than the Dependency Graph, it gives more opportunities to identify complex issues, patterns and anti-patterns in source code.

Queries and Rules Explorer

NDepend contains a set of predefined grouped rules to identify code smells and potential problems:

Rules are built with LINQ-based CQLinq language, every rule can be edited and contains explanations with links to appropriate help articles:

The rules are based on metrics, calculated throughout the project assemblies. Very brief explanation of the most used metrics can be found in this PDF document and the full explanation is accessible in the appropriate help article.

I would also say that the rules are pretty strict, some rules provoke debates, some of them are mutually exlusive, for example Microsoft assembly System.Web breaks thousands of rules and hundreds of critical rules. I wouldn't say that its code quality is so bad, because it is probably on of the most used and supported (thus one of the most valuable) .NET assembly. Therefore I wouldn't recommend to be overfocused on that, considering that working code is always more valuable than pefect code. On the other hand you are free to adapt these rules to the quality criterias that are followed or should be followed by your team.

Thansfully, the query language is pretty intuitive and straightforward, it shows methods and properties' hints, supports intellisense, so, generally you don't need to study a lot of documentation and manuals to adapt these rules to your project. Therefore the idea is that you've got a set of common predefined rules and you can very easily adapt existing or add new rules according to your needs.

If you need to exclude some additionally generated code

Project Report

NDepend project report can be generated as a result of project analysis. It is an HTML-based reported, which can be hosted and shared with other people even if they don't have NDepend installed:

The report is a very simplified version of NDepend UI to provide lightweight analysis results.

Summary

NDepend contains a set of tools which can help in analysing of complex .NET projects and providing analysis results: metrics on different levels of project hierarchy, dependency tools like the Graph and the Matrix, customizable project queries, etc.

The next article is dedicated to the most useful NDepend's feature I have found: Code Quality Regressions and Ensure Quality From Now!

No comments:

Post a Comment