
As a professional developer, my job is to created valuable software. And I think that one of the way to achieve this goal is by producing high quality code. It means that the coupling has to be low, the components clear and concise, the code coverage ration must be high and a lot of other things. At least this is how I defined quality when it is related to programming.
Code quality is an abstract concept and can be interpreted in several ways. You can find “best practices” depending on your programming language and paradigm. As an Object Oriented Programmer working with C# I heavily rely on the “Clean Code” concepts and the SOLID principles (more here).
Principles and concepts are mandatory for every professional developers. Yet when working on a huge code base it is difficult to know if your concepts are respected everywhere in your application. There are tools to help you with that and I had the chance to be able to test one of them, called NDepend and I will introduce it in this blog post.
What is NDepend?
NDepend is Visual Studio extension that run static analysis on your .NET solutions in order to generate metrics related to your code to help you improve the general quality of your applications. It displays these metrics using lists, graphs, matrixes, tree maps and charts. And of course it is possible to customize all of it.
How does it work?
I could try to describe every features available in this tool but instead I will just use an example to show you how it works and what it is possible to do with it.
To do the demonstration I will use a .NET solution from an open source project on GitHub called Serilog. This project is a .NET logging library easy to use and extensible.
Once I have installed NDepend and open the solution on Visual Studio I can attached a new NDepend project (.ndproj file) to the solution. Everything is achievable from the NDepend menu inside Visual Studio, you don’t need to run third-party tools.
From there I can choose the dynamic libraries (DLL) I want to analyze that exist in the solution. If I want I can exclude libraries I don’t want or that are not relevant. After this you can start the analyze right away and see the result of it after a few seconds (it is really fast). Once it is over you are able to display the dashboard which will give you an overall idea of your code quality with some metrics.
On this dashboard you are able to see the total number of lines of code, the number of types, the average method complexity (1.67 is definitely good). There are a lot of charts that will allow to see the evolution of some metrics over time. And there is an area dedicated to “code rules”, for the moment you can consider this as a “warning” counts, I’ll come back to this later. Of course this dashboard is customizable if you want to get rid of some metrics to put others instead.
Visualize the dependencies
Once your solution has been analyzed you can display a dependency graph at an assemblies level to have a quick look at the solution organization and to check where the external libraries are used.
For example on this graph we can see that the test project uses NUnit as testing framework and not the default one provided by Visual Studio. There are not much external dependencies.
It is also possible to generate dependency graphs at a namespace level to get a more detailed view of the solution. For the following graph I only selected namespace from the solution and not from the external libraries.
Do not worry if you think that this graph is unreadable, you can have coloration when putting your mouse over a node and you can choose to display only a portion of the graph. You can also see that there are some red edges on the graph, it means that some namespace are mutually dependent (they use each other) and therefore are highly coupled. Maybe you allow that, maybe you don’t, but this is a first indication that quality can be improved in this area.
Code rules
NDepend comes in with a huge set of code rules that aim to pinpoint the types or methods in your application that can be improved following some “best practices”. Here are the rule categories available.
On the left panel you can see all the rules related to the “code quality” group. The analyze have found that 2 methods might be too big and 6 methods might need some refactoring. By clicking on a rule it opens a new window giving you the details for this rule and the result.
This is where the real fun starts! The rules are “open-source”, they are written in a LINQ-like syntax (called CQLinq) and you can edit them at your convenience to match your needs. And of course the result in the lower panel is updated in real-time. For me this is the big feature of NDepend, you can request your code with an user-friendly API allowing you to check a huge amount of details. You can really customize the rules the way you want to match your quality requirements.
Add more visualization
The way I enjoyed the most working with NDepend is when I bind the queries editor with the tree map view. This way I can locate in the blink of an eye the parts of my project that match my query. And then I am able to see the components of my applications that match several queries. This can be a powerful indicator to track down the lack of quality. For example I will display all the methods that can have a lower visibility (it is a NDepend base rule in the “visibility” group).
I can see that this rule is “violated” in every projects but especially in the test project. In this case it is a false alarm, since the test methods have to be public in order to be executed by the test runner. What I can do is exclude the Serilog.Tests library from the NDepend analysis or I can update the query. Here is the original rule:
// <Name>Methods that could have a lower visibility</Name> // This rule tells which methods can be declared with a lower visibility. // (like 'private' is a visibility lower than 'internal' which is lower than 'public'). // Reducing visibility is a good practice because this fosters encapsulation // and with it maintainability and extensibility. warnif count > 0 from m in JustMyCode.Methods where m.Visibility != m.OptimalVisibility && !m.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) && !m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) && // If you don't want to link NDepend.API.dll, you can use your own attributes and adapt this rule. // Eliminate default constructor from the result. // Whatever the visibility of the declaring class, // default constructors are public and introduce noise // in the current rule. !( m.IsConstructor && m.IsPublic && m.NbParameters == 0) && // Don't decrease the visibility of Main() methods. !m.IsEntryPoint select new { m, m.Visibility , CouldBeDeclared = m.OptimalVisibility, m.MethodsCallingMe }
And now I will update it to exclude the test methods by adding the following condition:
!m.HasAttribute("NUnit.Framework.TestAttribute".AllowNoMatch()) &&
And the tree map view is now updated.
We can see that there is a lot less “blue” in the test area but some is remaining. And these maybe are some refactoring opportunities we would have missed if the complete DLL had been excluded.
In this blog post, I only scratch the surface. NDepend provides a lot more functionalities to improve your .NET code quality, you can find some of them in a presentation I made a few weeks ago (available here).
As a professional developer focused on software quality, NDepend is a great tool. I personally love all the visualization and the customization it provides, it is refreshing. I can create and/or reuse all the rules I want to match the level of quality I desire. And I still have a lot to discover in the potential it offers.
If you would like to know more or have some details on more specific parts of NDepend, let me know.
See you next time!
Awesome!!!
LikeLike