Software projects, by nature, have a propensity for getting out of hand. No matter how tightly we adhere to our carefully crafted development processes, despite diligent and methodical software designing and refactoring, the elusive software project always seems to manage to get away from us and mask its true nature from our prying eyes. Something close to a bajillion dollars has probably already been spent in attempts to tame the software project and convince it to open up and reveal its inner secrets and with increasing success. It has certainly been my experience that the software projects I’ve worked on in the last five years are much more transparent than they were fifteen years ago. This is in no small part due to the fact that I am no longer a teenager banging out Win32 applications in Borland C++, stumbling my way through APIs until an acceptable solution to the problem in hand somehow occurred. However, the view that software projects are becoming increasingly transparent is also shared by my peers. The general consensus is that the tools and development environments have played a significant role in this, a significantly larger role than the maturity or structure of the code being developed.
This is the key observation that I have made in thinking about the problem of software project wrangling. Despite advancement in the languages, environments, and tool-set, the code itself doesn’t seem to have become significantly more transparent. Bear in mind also that I am not describing the “API of complete awesomeness” that represents years of careful labor and also accounts for about 0.1% of the code developed each year. I’m talking about the other 99.9% of “copy/paste/tweak/pray” code that represents the bulk of what you and I will be maintaining, supporting, and extending for a notable portion of your software development career. Given this (rather lofty, sweeping, and completely personal-opinion-based) assumption, thought moves again to the area in which our wrangling efforts have advanced: the tools. If we can’t get people to architect more elegant solutions, perhaps we can find less painful ways to pry open Pandora’s box and examine the gifts our coding predecessors have left for us.
One tool in my arsenal for this task is NDepend. Tools and development styles will always be very personal. There are tools that I use for which others find no benefit and similarly there are those tools that have been recommended to me that just don’t seem to do what I need. However, I can highly recommend that any developer at least evaluate NDepend for their own use as it brings a rather unique perspective to the problem of analyzing even the most elusive of software projects.
What does NDepend do?
Arguably one of the most important questions to ask when evaluating any new piece of software is what it does. Put simply, NDepend analyzes your project and tells you stuff about it that might otherwise be difficult to discover. It breaks down a software project into its most basic components and then lets you query and visualize the sum of those components in extremely powerful ways. NDepend provides a wide variety of features for software analysis but undoubtedly the majority of its value lies in the power of CQL. The Code Query Language is not unlike traditional T-SQL in both syntax and the type of problem it is trying to solve. However, where SQL is designed to query data stores, the CQL language is designed to query software project information. This has several applications from code navigation and searching to coding quality evaluation and a whole host of standards metrics calculations.
In short, NDepend provides an incredible amount of information about how your project is glued together and how every field, method, type, and assembly is structured as well as how each of those elements relates to one another. When you first run NDepend upon a solution or set of assemblies, the amount of information that is presented can feel a little overwhelming. However, as you start to present small problems for NDepend to solve it quickly becomes clear why all of this information is very necessary.
Where do I start?
The best way to start working with NDepend is to point it at an existing set of assemblies and run an analysis. Then we can start to pick through the individual parts of the analysis and start to benefit from the information that is presented. For this purpose I have down-loaded the source code for an open source project called NArrange. This provides a nice publicly available solution on which to test NDepend such that the samples in this article can easily be reproduced.
Step 1 – Download and Install NDepend Trial
You can download a trial version of NDepend here.
Step 2 – Analyzing a Solution
First make sure that you build your solution, either using Visual Studio or via MSBuild or another tool. NDepend analyses a set of assemblies rather than a project or solution.
From the NDepend start page, select “Analyze: a set of .NET assemblies”. This will display a file selection dialog which we will use to browse to the NArrange libraries. I navigated to the NArrange.Tests.ConsoleApplication bin/Debug directory as this contains many of the solution assemblies that we wish to analyze. Once we have selected a set of assemblies, NDepend will being to run its initial analysis. This should take about 30 to 60 seconds depending upon system load and performance.
Once the analysis has completed, NDepend will display the current project in its main window as well as opening a browser that contains a full analysis report.
There is a tremendous amount of information in this report and it will take a while to become familiar with all of the data that is being presented. To that end we will look at each of the sections in turn and adopt a step by step approach to understanding why this information is useful.
Analyzing the Analysis
Let’s first look at the project map (or VisualNDepend View). If you close the browser that contains the NDepend Report you’ll see that the NDepend gui has been updated. At the top is a section containing this view.
This looks a little like a topographical analysis of the moon with yellow writing on it. In truth this is a lot like a lunar map except instead of showing the peaks and troughs of the moon’s surface it is showing the topography of our project. The NArrange solution is split into several different projects, each of which compiles into an individual assembly. The thin yellow lines separating sections of the map represent the boundaries between these assemblies. Each of the little gray circles that fill in those yellow squares represents a group of code within that assembly. In essence you are looking at the project as though it were arranged into states and counties. Each county represents a type whereas each state represents an assembly that contains several of those types. You can run your mouse over the project map and see that each gray area will turn red as you mouse over it. Additionally, the name that gray area represents is displayed. The purpose of this project map is to give you a visualization of the layout of the whole solution. It also plays into a lot of the deeper analysis functions that NDepend has to offer and becomes a center-point for visualizing the location of code in the project.
Start by clicking on one of the gray areas. Note how the class browser window to the left is updated when an area is clicked. This allows you to navigate your code visually while seeing the familiar class browser tree-view for the selected code element. Alternatively you can click on a method or type in the class browser and see the visual view update by highlighting the appropriate area of the map. Selecting an assembly in the class browser will highlight that entire assembly in the visual view pane. The class browser gives a very zoomed in perspective of your project, whereas the visual view gives a fully zoomed out view of how a particular element relates to the other elements in the full solution. I find a combination of the two to be a very powerful and expedient way to navigate a solution.
Abstractness vs Instability
Lets open the report that was generated after the initial analysis again. To do this we can click the button at the top of the Home ribbon.
The set of links at the top of the report allow you to navigate the report contents. Click the Assemblies Abstractness vs. Instability link to be taken to a graph that pinpoints this information for each assembly that was analyzed. This graph contains two major zones of pain and uselessness, leaving a sweet spot in the middle. Assemblies that are both abstract and unstable live at the top-right of the graph, in the zone of uselessness. This is to indicate that pairing abstractness with instability serves little purpose. Assemblies in the bottom-left of the graph are very stable and tightly concrete. This can lead to significant pain when they are maintained or extended as they are so tightly coupled and interwoven that making even small changes can require significant effort. The sweet spot in the middle represents the correct balance between abstraction and stability. This can be a good visual aid when learning new code or revisiting code you haven’t touched for a long time. The pain points and potential pitfalls are identified quickly.
In this graph we can see that the NArrange assemblies are sitting firmly in the green zone. The NArrange.Core assembly is the most abstract of the bunch but is also just stable enough to balance that level of abstraction. It is expected that most test assemblies will cluster in the bottom right area of the graph, which is not a bad place to be. Most test assemblies are fairly unstable and employ no abstraction as they are intended only for the purpose of testing a single type or set of known methods.
This very brief overview was intended to scratch the surface of NDepend and give a feel for what this tool is trying to accomplish. I’m working on more articles around the excellent CQL language and deeper features of NDepend. These articles will be the basis of a training for some brown bags as well as the source material for more blog posts on this topic. Meanwhile, here are some resources that are other great starting points for learning more about this great tool.
Stuart Celarier put together an excellent cheat sheet for NDepend that can be found here. This is one of those sheets you just want to print out, laminate and either hang on the wall or find a place on your desk, perhaps even as a mouse mat.
Other than that, one of the best ways to learn the tool is to simply install it and then start poking around with the analysis and learning by using. Analyze your current project assemblies and then start navigating using the NDepend interface. Play with some of the CQL queries (it will make reading future articles on CQL simpler because you’ll be more familiar). Make sure to install the VisualStudio and Reflector addons as these make full circle integration a part of your life. Other than that, I look forward to putting together my next NDepend article on using CQL to really understand and learn about how your code is put together and where it can be improved.