.NET Nakama

Improving your .NET skills

Static Code Analysis with NDepend

May 18, 2021 (~14 Minute Read)
STATIC CODE ANALYSIS SOFTWARE QUALITY CODE METRICS REVIEW

Introduction

Static code analysis is the examination of the source code that is performed without running the program (just by “reading” the code) to identify code quality issues, vulnerabilities, violations of coding standards, etc. In .NET Nakama (2021, May 4), we have learned about static code analysis, dynamic code analysis, how they can help us, their limitations, and how to choose the right tools depending on our needs.

TL;DR – Static Code Analysis tools provide diagnostics (about code quality, coding standards, etc.) early in the software development process, resulting in a lower fixing cost. But they cannot identify whether the business requirements have been fulfilled in the code. They should be used along with code peer reviews to boost the software quality.

In this article, we will investigate the NDepend static code analysis tool, we will take a tour in its features and I will share my experiences using it. So, this article is not a tutorial on how to use NDepend but, mainly focuses on its understanding, what it provides and how it can help us.

NDepend

The NDepend static code analysis tool provides several features that can help us improve the quality of our .NET code, avoid complexity in the project and make better structural decisions. For example, it can help us monitor several code metrics, detect regressions and code smells, generate diagrams and reports, and query and visualize the code. It can analyze .NET 5.0, .NET Core, .NET Fx 4.x, ASP.NET Core, Blazor, Xamarin, Unity and UWP applications.

NDepend is a desktop application that we can install in our Windows operating system (it is not a web application). It has its own standalone user interface that can be used regardless of the IDE (Visual Studio IDE, Visual Studio Code, Rider, etc.) that we are using to write code. However, NDepend integrates with Visual Studio IDE (as an extension), so we can use its features directly from VS.

NDepend provides a fully functional 14-days trial version, just to see if it fit your needs. The rest of the available NDepend editions require payment. So, a free edition is not available.

From my understanding, the three core features of NDepend are the following (which we will investigate in more detail in the following sections).

  1. Code Rules and Technical Debt.
  2. Visualizations.
  3. Integrations.

Download and Install

Let’s begin from the basics and see how to download and install the application. To download the 14-days trial application, you should provide your email and then you will receive the installation zip file.

  • To install NDepend, just unzip the files in a private application folder on your machine. It is suggested by NDepend to not unzip it in the ProgramFiles files path e.g. %ProgramFiles%\NDepend.
  • In the folder that you have unzipped NDepend, you would see several files as shown in Figure 1 We have two options to use NDepend:
    • Install and manage (re-install & uninstall) the VS IDE Extension of NDepend. I would recommend it because you can use NDepend features directly from VS. If you are using another IDE or code editor (e.g. Rider or VS Code), then you do not need to install it.
    • The VisualNDepend.exe is the standalone graphic user interface (GUI) that can be used independently from your IDE. So, if VS is laggy in your machine/project, you are using a different IDE or you just want to use NDepend separately, then this is your choice. Create a shortcut in your favourite place and we are ready to go!
The NDepend files and the main starting options.
Figure 1. - The NDepend files and the main starting options.

In Figure 1 we can see that additional executable files exist. Let’s have a quick look, to see what it provides:

  1. NDepend.Console.exe: A command-line executable that can be used to run the analysis and build reports. This would be great for command-line lovers 😛 and for continuous integration (CI) purposes.
  2. NDepend.PowerTools.exe: A set of small open-source programs (examples) demonstrating the NDepend API syntax and capabilities. This API contains a set of interfaces to develop custom sophisticated .NET static analysis tools 👍.

NDepend provides great tutorials (with videos) to getting started. You can check it out for more information, e.g. how to analyze your project either by using the Visual Studio IDE or by using the NDepend application.

Code Rules and Technical Debt

As we have seen in .NET Nakama (2021, May 4), the static code analysis tools are reviewing the source code automatically based on multiple code rules. This is also true to the NDepend tool, but there is more. NDepend provides the CQLinq feature (with a non-standard-C# warnif prefix), which give us the ability to query the code with C# LINQ. The idea is to query the code with CQLinq the same way as relational data is queried with SQL.

For example, the following CQLinq code query could be used to get a warning for the methods that have been refactored since the last release and are not thoroughly covered by tests.

Warnif count > 0
From m in Application.Methods
Where m.CodeWasChanged() && m.PercentageCoverage < 100
Select new { m, m.PercentageCoverage }

NDepend provides around 200 default queries and rules (in CQLinq), which are described in the NDepend Rules Explorer. As you may have guessed, we can edit these queries to be adapted to our needs, but we can also create our custom rules with CQLinq.

In Figure 2, we can see that there are several rule categories available, such as Quality Gates, Code Smells Regression, Hot Spots, Code Smells, API breaking changes, Naming Conventions, Security, etc. In each of these categories, we can see if there are issues and the number of issues in each category’s rule. In this example, we can see that 9 API methods have been affected, which may result in API breaking changes from the previous baseline (i.e. an older analysis result). This is an important feature for API developers to provide backwards-compatible APIs.

Another great rule category is the Code Smells Regression which provide code rules that are applied to new code (from now on). Let’s assume that currently our code is not in a good shape and has no high test coverage. There are a lot of teams that would schedule to fix the existing code issues and agree that all new code will follow some basic quality principles and would be covered with tests. That’s exactly the information that Code Smells Regression rules provide us, as we can see in Figure 3.

When we click on a found issue we will see (Figure 4) details about the related methods or/and types, their names, etc. In this way, we can navigate to the code that has the issue. Also, we can see the CQLinq rule code, its description and proposed solutions to fix the related issue.

The rules for API breaking changes.
Figure 2. - The rules for API breaking changes.
The Code Smells Regression rules that are applied for new code.
Figure 3. - The Code Smells Regression rules that are applied for new code.
Details about the methods or/and types that match with the related issue (in a VS light-theme).
Figure 4. - Details about the methods or/and types that match with the related issue (in a VS light-theme).

Another nice feature that NDepend provides is the Technical Debt Estimation, which is calculated based on code rules and on other parameters to be as realistic as possible. NDepend provides the following two metrics on each identified issue (as shown in Figure 5), to show an estimation of the business impact if it left unfixed. A summary of the debt is also provided in the NDepend dashboard, which we will see in the following section.

  • The technical-debt, is the estimated man-time that would take to fix the issue.
  • The annual-interest, is the estimated man-time consumed per year if the issue is left unfixed.
The debt and annual-interest metrics per identified issue.
Figure 5. - The debt and annual-interest metrics per identified issue.

Visualizations

NDepend provides rich visualization features to present code metrics, trend charts and architecture diagrams. In general, I am a big fan of code and architecture visualizations. They help me have a clearer view and better understanding of the projects and better communication with my team members.

Dashboard

The first thing that we can examine in NDepend is its dashboard (see Figure 6) in which we can see a summary of several metrics and trend charts, in a glance. We can explore the technical debt information, the number of prioritized issues and information based on a baseline. In this way, newly written code and refactored code can remain clean and follow the defined rules. We can easily monitor the testing coverage and see our progress, which can motivate us to increase it further.

Trend charts (for example see Figure 7) are presented in the dashboard, which can be used to monitor different metric values over time, such as Lines of code, Number of issues, Code coverage ratio, etc. Finally, we can create reports (in HTML format) that reflect the status of the code to be shared with developers and management.

Summary of several metrics in the dashboard.
Figure 6. - Summary of several metrics in the dashboard.
Several trend charts in the dashboard.
Figure 7. - Several trend charts in the dashboard.

Visualizing Code Metrics

NDepend provides a visualization of the code metrics in a treemap. For example, in Figure 8 we can inspect which parts of the code need more tests. We can select many more metrics such as Cyclomatic Complexity (CC), Percentage Comments, Nesting Depth, etc. In combination with the Size and Level options, we can visualize different aspects of the code based on our needs.

Treemap of the percentage coverage metric.
Figure 8. - Treemap of the percentage coverage metric.

Architecture Diagrams

Understanding the software architecture of an existing project is something that can be difficult for junior developers or new members of a team. NDepend can generate architecture diagrams that present the dependencies between its modules (see Figure 9). This visualization can help developers and architects to understand, improve, maintain the software architecture and make better structural decisions (e.g. when managing legacy code or on refactoring).

An example of a Dependency Graph.
Figure 9. - An example of a Dependency Graph.

The same data can be visualized by using the Dependency Matrix feature, which is a compact way to represent and navigate across dependencies between components (see Figure 10). From the dependency matrix, we can see if the codes used a layered structure, if dependency cycles exist, if high cohesion exists, etc.

A Dependency Matrix example with dependency cycle.
Figure 10. - A Dependency Matrix example with dependency cycle.

NDepend Continuous Integration

NDepend supports Azure DevOps Services (formerly VSTS), Azure DevOps Server (formerly TFS), and provides plugins or/and instructions to integrate with some CI providers, such as TeamCity, Jenkins, SonarQube, and more. In addition, the NDepend.Console application could be used for other cases.

The Quality Gates is an important feature that can be used to fail the build when certain criteria are not verified. In this way, the selected code quality criteria must be enforced before releasing and eventually, before committing to source control.

Review

I have used NDepend in my hobby projects to have a better understanding of how it can help me in practice. About the installation process, some people will argue about the manual installation, but it’s an easy task that you will do it once.

From the results of the first run/analysis, I was amazed by the quality of the issues that it found, with a very small number of false positives, even for a newer type of projects, such as Blazor. For my projects, NDepend found several issues that require improvement. Some of the issues were minor (e.g. naming conventions) but some of them were important (e.g. dependency cycles) that made me re-think the architecture of some parts of my code.

After introducing new code to fix some of the issues, additional issues appeared 😮. Apparently, I haven’t included unit tests for my new code (Code Smells Regression) and some of my changes broke my library API signatures (API breaking changes). For me, these issues or warnings provided me with helpful suggestions to make me think differently. The percentage of the “accepted” testing code coverage is configurable. So, you can set your team’s decision to get meaningful notifications.

Familiarizing with NDepend GUI will require a small learning curve, but it will be required. Fortunately, NDepend provides very good documentation and guiding information inside the application.

For me, it’s important to have the appropriate after-sale support from the tools or services that I use. I contacted via email NDepend to ask some questions and also to report some possible false positives. I received a quality response quickly, that answered all of my questions with suggestions, and they also thanked me for the false positives report.

In .NET Nakama (2021, May 4) we have seen some important factors that we can take into account when choosing a static code analysis tool to be based on our needs. So, let’s see how NDepend is doing:

Important Factor Result
Programming Language C# & VB.NET (it also provides solutions for C++, Java, and Python).
Integrations Provide a Visual Studio IDE extension. Regarding CI, it supports: Azure, TeamCity, Jenkins, Bamboo, AppVeyor, SonarQube, CruiseControl.NET, FinalBuilder, TFS 2013, and NDepend.Console for other custom cases.
Suppression Feature Yes, by using tags or a global suppression file or assembly.
Rules Extendibility Feature Yes, by using the CQLinq code query.
Summary Metrics Yes, it provides a dashboard in which we can see a summary of several metrics and trend charts, at a glance.
Collaborative/Reporting Features Yes, we can create reports (in HTML format).
Fast Analysis Results Very Fast. For my project, a few seconds were needed. NDepend promises the same performance even for a very large codebase.

Summary

NDepend is a static code analysis tool with many features. In this article, we have learned about the three core features 1) Code Rules and Technical Debt, 2) Visualizations and 3) Integrations. Also, we saw how they can help us improve the quality of our .NET code, avoid complexity in the project and make better structural decisions.

The dashboard, the visualizations, the clear issues and how-to-fix instructions make software development a gaming experience, which motivated me to reduce the issues and increase the test coverage. So, it can help us improve our code and our skills (by educating us on the rules to follow). It is an insightful tool that guides developers in fixing essential issues, providing the visualizations to understand, improve, maintain the software architecture and finally make better structural decisions.

I would recommend you give it a try in your projects (a 14-days trial version is available) and share with us your experience. Did it found something that you couldn’t imagine? Was it helpful? Did you like the visualizations?

If you liked this article (or not), do not hesitate to leave comments, questions, suggestions, complaints, or just say Hi in the section below. Don't be a stranger 😉!

Dont't forget to follow my feed and be a .NET Nakama. Have a nice day 😁.