In a software engineering world, working with large and complex projects is pretty much normal. We design, code, and that’s we do. When the project grows bigger, every new feature added to the system makes our codebase more complicated and harder to maintain, not unless if your application architecture is carefully crafted. In reality, many software applications (legacy app) are built many years ago that were poorly architected and maintaining them is as painful as hell in which it could leads to a full software rewrite, not to mention the cost of a full software rewrite. Even today, I’ve seen a few projects that were designed poorly and that is because they don’t review code, and nobody is looking at the entire architecture of the system. There are many reasons why this happens:
- (1) Developers are afraid to update an existing code because they might break something. This could lead to code duplication because they will create their own method that does the same thing.
- (2) They lack developers and they need to keep up with the timeline that the client has to expect. Sometimes a developer works for 3 or more projects at the same time.
- (3) Code are left undocumented due to point #2.
- (4) Majority of the developers doesn’t care about performance; they just write code that runs and that’s it.
- (5) Developers are not guided property on how to make good code.
- (6) They don’t have software architects that crafts the design of the system and enforces code quality.
Crafting a good system requires a good software architects or even a Sr. Developer with more practical real-world experience that knows how to build a better system based on the business goals that are flexible and features can be easily added or removed. However, reshaping an existing system to become more performant and flexible is a different thing, especially if you are not familiar how the whole system works. An architect/developer cannot just easily walk through thousands of lines of code manually and identify code smells. In other words, it is very difficult to pinpoint at specific problems and proposed potential solutions without a precise tool. Using a right tool for systems analysis helps you easily identify what areas needs to get fixed and suggests where to alter the design to enhance the existing architecture before it gets bigger and more complicated to maintain. NDepend can do that.
NDepend is a tool for static code analysis which the primary goal is to let you analyze your application and to get a clear idea about the technical debt, violated rules and it’s severity, cross dependencies between objects, level of association between them and to know the condition of your codebase easily. With that being said, NDepend is a tool designed to give you a higher level of static analysis that helps you design a better system, rather than writing more correct code.
Luckily, I had the opportunity to review NDepend last Month, but I didn’t get the chance to give it a shot that time because I was very busy with projects. Fortunately, I am able to find some time this week and I am very excited to share with you the experience that I have with NDepend.
In this article we are going to take look at some features that NDepend has to offer. To get started, let’s setup NDepend by following a few steps below:
- Download NDepend here: https://www.ndepend.com/download
- Unzip the folder to location other than
- Click the
VisualNDepend.exeapplication and activate the product with the key
- Install NDepend Visual Studio Installer (
NDepend mainly works as Visual Studio plugin and can also be used independently using its own UI called Visual NDepend. It integrates into Visual Studio 2010 – 2019 (the latest version as of this time of writing), TFS, Azure DevOps (VSTS) and in any other CI platform.
Let’s Get Cracking!
After setting up NDepend, we can now start exploring our codebase and see what benefits we can get with NDepend.
In this example, I’m using
Visual Studio 2019 (Preview) to load a sample project with
NDepend version v2019.2.6.9270. To start analyzing a project, navigate to the Visual Studio Extensions tab and then select NDepend > Attach New NDepend Project to Current VS Solutions:
Figure 1: Analyze a new project
A popup dialog should show the list of projects within the Solution that you want to analyze. If you want to analyze a specific project only, you can use the “
Filter” box to exclude unwanted projects. Here’s the filter tip pattern:
- Negative filter(s) prefixed with the minus “
-“ character can be used to filter out assemblies.
- Positive filters(s) like “
YourProjectName” can be used to refine what assemblies to analyze.
- An assembly is matched when it satisfies all positive filters and no negative filter.
- Filters are case-insensitive and separated by space.
In my case, I only wanted to analyze one project and filtered out the rest within the solution for the simplicity of this review. I went ahead and clicked the “
Analyze a Single .NET Assembly” button to let NDepend begin the code analysis process.
After NDepend finishes analyzing the code, you will then be presented with the following dialog below to guide you on what to do next:
Figure 2: NDepend help dialog
And an HTML report version will also be generated as shown in the figure below:
Figure 3: HTML view of Application Code Metrics
That was very cool! I mean, in just a few seconds, I was able to get the data points (Code Metrics) summary of what’s happening in the project and provides me a few diagrams to visualize the codebase at a glance.
Let’s take a detail look of what’s going on there. Let’s head on to the “
Figure 4: NDepend Dashboard
Notice that the NDepend Dashboard is pretty much the same as the Application Metrics HTML page version where it displays the following data points summary:
- Number of Lines of Code (LOC) – NDepend refer this as Logical LOC rather than Physical LOC. Logical LOC metric are calculated based from the generated PDB file when the code is compiled.
- Number of Types – a metric that counts all application types that are not generated by the compiler.
- Comment – a metric that returns the percentage of comment compared to the Number of Logical LOC.
- Debt – a metric that shows the ratio of technical debt compared to the estimated time it would take to rewrite the entire codebase.
- Coverage - is metric that shows the coverage of data that you imported.
- Method Complexity - a metric that serves as a way to quantity complexity in your code.
- Quality Gates – a metric that defines quality goals that must be all reached before pushing the code to production.
- Rules – a metric that displays all the rules that were violated and passed.
- Issues – a metric that displays all the issues that falls into a certain rule and its severity.
One of the great features that I like about NDepend is that all data in the dashboard are interactive. Clicking on each data points will allow you to drill-down into the details and modify any rules based on your business needs. For example, clicking on the
Rating under the
Technical Debt metric will show the following details:
Figure 5: Queries and Rules editor
The code in the upper part is a C# LINQ query (
CQLinq) that list the types that have the most debts, or in other words, types with issues that needs more effort to get them fixed. The bottom part shows the detail of the result such as the number of issues, annual interest, debt ratio, etc.
In this particular codebase, NDepend gives me an insight that the current codebase
Technical Debt rating is
B and it would take
6 Days and
1 Hour to reach an
A rating, which is
7.28% of the amount of time it would take to rewrite the entire codebase. In other words, the Technical Debt metric is used to estimate the cost to fix issues in code. Keep in mind that the settings for calculating the Technical Debt can be reconfigured based on your development teams’ setup. You can see the settings under Extensions > NDepend > NDepend Project Properties > Issues and Debt:
Figure 6: Issues and Debt configuration
The results of the data points metric in the Dashboard are based on the
default rules built-in to NDepend. These rules are written in
CQLinq to track code smells and other stuff within your codebase. There are over
200 Rules by default which are classified in categories below:
Figure 7: Queries and Rules Explorer
Queries and Rules Explorer window allow us to drill-down into the details of the information about the code smells by just clicking on the item, and gives us an information on how fix those rules that were violated. All these Rules are written in CQLinq that are compiled and executed on the fly, making it easy to modify a certain rule to customize your needs. You can also write your own custom rule if you would like. For more information about Code Rules, see: https://www.ndepend.com/default-rules/NDepend-Rules-Explorer.html
While all data points displayed in the Dashboard are very helpful in code analyzation, what interests me most are the columns in the right: Quality Gates, Rules and Issues.
Figure 8: Quality Gates, Rules and Issues metrics
It interests me because it gives me an insight of the potential issues and rules that were violated in a glance by just looking at the red values. Based from the data points above, it tells me that the codebase failed
1 Quality Gates,
58 rules were violated which
6 of them were critical, and
72 issues that were tagged as
Looking at these statistics sounds alarming to me, so I went ahead and drilled down to its details to explore more information about them. I started with the failed Quality Gates by clicking on the
Fail status and then I was presented with this information:
Figure 9: Quality Gates
This information tells me that the codebase has
6 rules that were critically violated as shown previously in the Dashboard’s Rules metric. Double- Clicking on the “
Critical Rules Violated” item presented me with this information:
Figure 10: Rules violated
This information gives me the idea of what rules that were violated and how many issues found for each rule that were violated. I was curious to see what method/code violated these rules, so I went ahead and clicked each item. When I clicked the “
Avoid methods too big, too complex” item, I was presented with this information:
Figure 11: Classes and Methods that causes the violation
From here, I was able to identify the methods in the codebase that violated the rules. This is very helpful because I am able to know the location and name of methods that are too big and complex without looking at entire codebase. That’s just saves us a lot of time! Adding to that, NDepend automatically provides us the description of the rule and how to fix issues of a certain rule as shown in the figure below:
Figure 12: Tips on fixing a violation
That’s just very very cool! With this information, we can start analyzing the code that was pointed out. This will give us the ability to weigh things in, whether it would make sense to refactor the code or not and work with the development team to collaborate on these areas to better enhance the application, and ultimately solidify the quality of the codebase.
Visualizing Your Code
Let’s take a look at another NDepend features. For security reasons, I have decided to use a different project to explore other features of NDepend. You can see the list of features provided by going to Extensions > NDepend:
Figure 13: NDepend features
Let's start looking at the
Figure 14: Dependency Graph
The figure above is the generated
Dependency Graph of the new project that I have analyzed. There’s nothing really fancy about it since the project is just a small one and only contains a few dependencies. The main goal of this diagram is to be able to see the relationship between assemblies within your codebase. Imagine how helpful this is when you are dealing with complex enterprise solution that contains a lot of projects on it. Having this visualization in a glance would surely help you identify the overall complexity of your codebase and help better understand the architecture of the project.
What’s cool about NDepend is that even the visualizations are interactive. This allow us to click on the item and see more information about the data. You can also right click on the item to explore more details and functions. For example, right clicking on the “
VMD.RESTApiResponseWrapper.Core” will allow me to see the “
Internal Dependency Cycles” on graph just like in the figure below:
Figure 15: Internal Dependency Cycles graph
This graph helps us to familiarize with how the class works and can give you direct access to the information for further analysis.
Figure 16: Dependency Matrix
Dependency Matrix helps us easily identify what namespace are dependent to the others. This is much more similar to the
Dependency Graph except that is illustrated in a textual and tabulated format which allow us to get more information about the assemblies and namespaces precisely. Understanding how the Dependency Matrix works is pretty much straightforward:
- The row to the left indicates the list of assemblies that were used.
- The column in the top indicates the assemblies that is using the assemblies in the row.
- The number indicates the members of the assembly involved in the relationship. For example the “
VMD.RESTApiResponseWrapper.Core.APIResponseMiddleware” namespace referencing the “
Microsoft.AspNetCore.Http.Abstractions” assembly that contains
12direct members on it: Figure 17: Dependency Matrix details
Figure 18: Code Metrics
Another form of visualization provided by NDepend is the
Code Metrics. A code metrics is a way to represent codebase through a
Treemap. A treemap is a visualization for displaying tree-structured data by using nested rectangles. The tree represents the usual structure of a program:
.NET assemblies contain
namespaces; namespaces contain
classes and classes contains
Code metric lets you browse through the codebase by navigating to a
tree. This is very useful when you see something on the map that is alarming. Here, we won’t see any alarming /code smells in our codebase since this project is pretty much small. However, when you are dealing with large complex applications, chances are this metric may show some alarming information. Alarming information normally shows a
Red color on the map. For more information, see: https://www.ndepend.com/docs/treemap-visualization-of-code-metrics
NDepend is a tool designed for a higher level of static analysis which helps you identify potential issues and code smells within your codebase. It gives you a high-level picture of the quality of the code which help you make decisions on how to better design a software.
To summarize, NDepend:
- is a tool mainly for software architects, or for people within your organization that make decisions on how to design a software.
- is a tool designed to give you a higher level of static analysis that helps you design a better system, rather than writing more correct code.
- can prevent system to get more complicated to maintain as it grows bigger by identifying code smells at the early stage and enforcing code quality rules.
- can identify whether your code respect standard quality rules
- can calculate standard metrics with various visualizations to better understand your whole project
- can estimate how much time it would take to fix the underlying issue – the
- can estimate how much time would be lost each year if the issue is left unfixed – the
Overall, I am very impressed with this tool. This will definitely help us on crafting a better system in our projects. I’m pretty sure there are still lot of features that I need to explore, and these are just some of them. So give it a try yourself and see the benefits that NDepend has to offer to better shape your software architecture in your organization.