This if part 2 of 2 of a series on NDepend and Code Metrics. In the previous post (here), I talked about why metrics are an important thing. In this post, I'm going to give a run down on NDepend in its latest version, version 6.
Right. Into the meat and potatoes of this series - NDepend.
Before we start, a small disclaimer - I don't often write pieces about software, so this is unknown territory for me. In my usergoup talk, I gave a whirlwind tour of the NDepend Universe, something I hope to replicate here, but it is in no means a full spread of the capabilities of NDepend - just the other day we managed to string together a code query to determine the classes that have fields that implement System.Collections, before ranking them on their equivalent Google PageRank - the swiss army knife of capabilities on your hands with this program is insane.
But without further ado, NDepend.
NDepend is a Static Analysis Tool for all things .NET. Developed by Patrick Smacchia and his team and NDepend, it runs and analysis over your code base, and provides a number of metrics and visualizations, as well as allowing you to run queries over your code in the form of LINQ statements, called CQLinq.
It comes in two different versions, Build Machine and Developer:
- The Developer version is priced at $325 USD, and offers almost full functionality of the GUI component. You'd generally use this if you wish to run the analysis on the whim of the, well, developer.
- The Build Machine license, at $488 USD is more for Continuous Integration environments, where you want the results to be visible to your entire dev team, through custom API wrappers, or through a tool like Team City. But more on that later.
On the mention of the NDepend API, I should probably describe what comes out of the box when you get NDepend:
There are five main components given on download:
- Visual NDepend: The GUI portion of NDepend, and perhaps the program you will use the most
- NDepend Visual Studio Plugin: I ran the Visual Studio plugin for v5, however, it seemed like it was the NDepend GUI inside of Visual Studio, so in that sense, I wont go into depth on this - I believe most of what is achievable in Visual NDepend is available through the VS plugin.
- NDepend API: Exposes a large number of the functionality in NDepend via a C# library. On a quick look, it seems like the API is the meat and potatoes of the show, and tools like the Visual NDepend make use of it. NDepend Console also looks like a Command Line interface for the API, which is very useful in applications where you require the base functionality of NDepend without writing your own wrapper.
- NDepend.PowerTools: is an open source collection of examples using the NDepend API to act as a tutorial on the API functionality.
- Integration: This is a new addition in v6, and unfortunately I was unable to have a play around with it (I'm not too familiar with SonarQube, another metrics platform, nor TFS, since I generally use Github). There is also now supported integration with TeamCity, which excited me, and no doubt will play with it in the near future.
First things first, lets have a play with the GUI, since the power of NDepend can easily be seen here.
When you open the program, you're met with this dashboard, giving you the option to open a recent project, or create a new one. Voat is one I created earlier, the source code for the Reddit-clone Voat.co.
Clicking on "add assemblies from vs solution," then selecting your desired Solution, you are presented with the ability to pick and choose what you track. To the left is your assemblies from your Application, to the right, any assembly that NDepend It's probably important to note it works off of the PDB files, so make sure you build your solution before loading it into NDepend.
From there, you are away laughing. Looking at the top of that panel, you can see two play symbols. The one on the left runs an analysis on your project, while the one on the right generates an HTML based report on the rules you have defined, and presents the information in such a way that you can embed it as a TeamCity artifact.
Once your analysis is completed, you're presented with this:
The dashboard provides a number of quick-access information to give you a snapshot on the results of your analysis. By default, NDepend comes with more than 150 rules that are run over your code, and each has a warning. If a rule that has been taged with the warnif command, it fires a warning off to alert you. In a build process, you can actually fail a build if one of these critical rules are broken, although you may want to make edits to them if you're adding this to an existing code base.
Queries and Rules Explorer/Edit:
Cutting right to the chase, this tool is totally amazing. As a student of Software Engineering, I am completely blown away at the capabilities of the CQLinq system. Be it naievity, or just the fact I'm sometimes easily excited by data, the ability to run queries over a code base, and get the results almost instantly can provide hours upon hours coming up with insights on your code.
I learnt much of the query language from the default rules provided by NDepend, as I wasn't too familiar with LINQ and Lambdas (I come from a wholly Java education), however, the other developers in my team are able to come over and use their knowledge of Vanilla LINQ to run queries themselves.
In v5, I had a little bit of trouble with this tool, I think because the code base I work on is relatively huge ( > 250,000 Lines ), however, in v6, the rule editor in is much more streamline, and a joy to use.
As an example, I have this query I wrote up - It gets all the types in the Voat namespace, and orders them by their Google PageRank. This highlights proportions of the code that perhaps are being used by a large number of types, and therefore, should perhaps be looked at to avoid a "God Classes" scenario further down the track. I've removed the Voat.Model namespace, as generally Models are going to be used in a lot of places as they are more of an Object representation of the Database, rather than actually meaningful code:
And instantly, as I type, I'm presented with the results. Most results will be instant, and NDepend has a timeout of 2 seconds for any query, so it's also encouraging you to create well thought out, efficient cost queries:
The cooler thing about this is as soon as you identify culprit classes, you are able to select the result, and then it opens directly into Visual Studio.
And this is barely scratching the surface. There are so many possibilities, It's really hard to confine this to a single post. I recommend you pick up the trial and have a go, or have a look at the CQLinq overview HERE
NDepend provides a handy tool to identify the dependencies your code has, both on internal assemblies in your code, as well as dependencies on third party assemblies. It was pretty difficult to illustrate how handy this was with Voat, as the code is relatively small, however, the cool thing about this is you can drill down right to a method level by selecting the little pluses next to each one.
Clicking on any one of the squares, also drills down into a dependency graph, which leads nicely into:
Basically the Matrix, in graph form, its quite hard to fit it all on one page, however, this can be key in determining whether or not your code is highly coupled, or not. You can set what the size of each of the bubbles represent, and the thickness of the edges represent the number of dependencies it has.
Pretty self explanatory.
Prior to v6, the metrics pane was a little drab, all grey scale, and somewhat confusing. However, now the pane is full of colour to identify the components in your system that may be causing trouble. In this following image, the more red a square is, the more lines of code it contains. You can set the "max" value to whatever you like, and in this case, is any method over 50 lines.
Hovering over certain components gives you some quick access information about the method you're currently on. Once again, playing with this will increase your understanding, and therefore, the usefulness of the tool.
The report bundles all the sections above into a static representation. It extracts the rules you've saved in your NDepend Project, and turns them into HTML. This is useful if you wanted to publicly (within your dev team, that is) show how healthy the code is after each build/weekly.
You can also view how each of your assemblies fare in the Abstractness/Instability graph that is also generated. Turns out in Voat, the code is relatively instable, therefore prone to change:
Phwoar, I think thats that for the briefest of flyovers on the NDepend GUI. I thoroughly recommend that should you get a trial, sit with another developer and figure out just how far NDepend can go in terms of rules you can write up, and the results you can get out of it - you can get a lot done in 14 Days.
The second component I'll look at is the API that NDepend provides, and as an extension, the NDepend.PowerTools code snippets that are provided to show you the capabilities of the API. Through my use of the API and Visual NDepend, I believe the GUI is built atop the API itself, and therefore, the API contains everything you need to implement the power of the NDepend Analysis into your .NET project.
Note: this API stuff is mostly based on my experience with v5, but I have double checked some notes on the documentation to determine the differences with v6, but I apologise if I whine about features fixed in v6
The NDepend.API.dll can be found in the Lib folder of wherever you unzipped your NDepend files. There are a couple things to note, however, when you choose to include the API into your project
- You need to set the dll to Copy False. Although you're only including the API dll, it needs to talk to the rest of the dll's in the Lib folder.
- In order for NDepend to talk to every other lib file, you need to edit the Assembly Resolver with the code found in the NDepend.PowerTools namespace (AssemblyResolver.cs)
- You must have all the files that you downloaded be present, that is, you must keep the VisualNDepend.exe and the Visual Studio plugin present when using the API in the same file structure you downloaded it in. I couldn't see a reason for this.
- If you're using a WebAPI/MVC application, you may have to add in a probing statement like in this Stack Overflow answer
One of my dissatisfactions with NDepend is the API insallation. It seems very voodoo magic-y to get it to behave, and the documentation is a little vague on a lot of how the install works. Even now, I don't exactly know what I did, but it works, and it is definitely something that would be neat to see fixed, or become more streamlined in a future version.
I use the NDepend API extensively in a work project I have been working on (more on that later), however, below is a Method from an API test I wrote as I was learning the in's and outs'
All this method does is recieve the project fro ma designated ProjectPath, and attach a Test Coverage output from dotCover (NDepend supports dotCover test coverage files to contribute to the metrics you gather from your code). and then prints out the analysis as it happens, before printing the time taken, then closing. Do note, however, you can only run the analysis through the API on a Build Machine License.
This is a fraction of what the API can achieve, as a majority of what is achievable in the VisualNDepend executable is also usable through using the API - refer to the NDepend.PowerTools project for more examples. Perhaps one of the most helpful tutorials was the Getting Started or Running NDepend Queries through the API
A pitfall to watch out for is the CQLinq reserved namespace, and the fact you cannot write raw CQLinq into your project, or at least, in the method I attempted to. To get around this, I test out queries in an NDepend Project file, save the ones I like, then when I run the queries through the API, they are included in the order in which they appear in the GUI. It's a simple workaround, and I'm not entirely sure that is how it is meant to be run, however, once again, the lack of extensive documentation is another con to the otherwise powerful API.
(In saying that, asking an NDepend question on Stack Overflow is generally guaranteed to get a response from Patrick! Kudos to the developer help!).
Once again, I've barely scratched the surface with the API, and definitely warrants a view. The Trial version unlocks all the features of NDepend, so if you're curious, have a play around, and you can soon discover how it works for you.
NDepend in our Developer Ecosystem
My summer, and now, winter project was incorporating NDepend metrics into a dashboard for Developers to see. Originally, we wanted to add it into its own TeamCity build process, however, these days, the architecture looks a little different these days.
What we do is have a Scheduled task run on a Friday night pull all the changes from the previous week, before building, running dotCover, then compiling it all together through NDepend. The most recent results are stored in a database for ease of access (the code base is relatively huge and ends up ~150mb of memory each Analysis loaded if we did it via NDepend). A WebAPI project loads up that database, and displays the information in handy graphs.
Hovering over a bar will show the related class/method, and its value, be it Lines of Code, or Cyclomatic Complexity. We also store averages as trends over time to analyse how our code base changes over time.
It wouldn't be a project without its fair share of issues.
- This is the second version of the code, I scrapped the original as it was prone to Memory Leaks and lack of Testing (turns out dotMemory crashes on dumping 7Gb).
- The initial design didn't handle new rules very well. I'm so used to academic coding, that enterprise software is a bit odd, but certain design decisions make sense to me now, and I continually implement them into my work, and my university work.
- I didn't, and still don't fully grasp NDepend. I'm still a student who hasn't finished their degree, and the full limits of my static analysis knowledge amount to perhaps 5 hours of university time, and whatever I have learnt along the way with NDepend. The current project is definitely an MVP, and I hope to extend upon it in the very near future.
Woah, what a lot in two posts. I'll summarise with a tl;dr
- I'm young an I'm naieve : I don't get paid to write code.
- Code Metrics can be important: Our mental models suck (sometimes), but we should really understand what our code does
- NDepend is Pretty Good at it: It’s a steep learning curve, but the possibilities are endless
- You can use NDepend anywhere: Just can’t use it to microwave your dinner (unless you have massive projects #laptopdev)
- NDepend is a Swiss Army Knife of capabilities: If you think you know NDepend, you’ll be surprised...
And Thanks to:
- NDepend (http://ndepend.com)
- Coda Hale (“Metrics, Metrics Everywhere” https://www.youtube.com/watch?v=czes-oa0yik)
- Patrick Smaccia @ Code Better (http://codebetter.com/patricksmacchia/2014/04/29/running-ndepend-rules-through-ndepend-api/)
- Microsoft Open Data (https://github.com/OData/odata.net) for use of your code.
- Ben Amor, the Fondue Ferrets and everyone else at Xero
As always, you can find me every so often on Twitter, @rack_jobinson, but generally an email is the best port of call: jackrob1994 - at - gmail - dot - com. I also have my github, which is currently full of University assignments, and little musings, and I hope to slowly add to it in the coming months, unlike this blog.