Disclaimer: Yes, I was given a pro license to NDepend. However, what follows are my honest impressions of version 2.12.1 of the tool on a real .NET 3.5 project. I have not evaluated the recent beta, so some of the issues noted below may be fixed in a more recent build.
To Patrick Smacchia: I apologize for taking so long to provide feedback on NDepend. I hope you find the feedback below useful. Thanks for giving me the chance to check out this cool tool!
NDepend is a complex and powerful tool for static code analysis. The basic idea is that you feed it your .NET assemblies, then you use the rich set of visualizations, Code Query Language (CQL) reports, and code coverage tools to analyze your codebase. When I say “rich set of visualizations,” I mean it. There are a slew of reports that are both eye-candy and useful at the same time. Within a few minutes of analyzing my first project, I had already discovered useful information, including an obsolete class as well as a unit test that was missing it’s Test attribute.
The power NDepend comes at a cost. The interface is immediately overwhelming, and though there is ample documentation available online, it still takes a while to discover all the tool’s capabilities. It also has a few quirks that can be irritating, and the UI feels a bit “glitchy” at times. Despite these weaknesses, I found the tool to be immensely powerful (CQL is awesome), and I can definitely see where it will be handy in the future. Read on if you want to know more.
When I launched NDepend, I notice that it looked and felt a lot like Visual Studio. It had the familiar “Recent Projects” pane on the left as well as links to common actions. There was a “Getting Started” pane with links to NDepend screencasts, and a button to install Visual Studio and Reflector integration. It also had a pane that to let you know if an update is available, a small but nice touch. I really like it when an application makes it easy for me to stay up to date.
Creating a new project was easy enough. After creating my project, I was able to add assemblies using any of several methods. I could drag-and-drop assemblies directly from Windows Explorer, I could add them manually by browsing, or (my favorite) I could add them by specifying a Visual Studio solution file.
Things took a turn for the strange here. At first, NDepend reported that it was unable to load any of the assemblies for my solution. It was nice enough to indicate why, apparently there were multiple versions of the assemblies buried in my solution. After some digging, I discovered that I had built my solution under the AnyCpu platform a loooooooong time ago. I had since switched to targeting the x86 platform, so I had some obsolete build output nested under my projects. This same “error” occurred even when trying to load the assemblies manually; apparently NDepend was still detecting assemblies with the same name but different versions. Once I figured it out, resolving the issue was easy: I just removed the obsolete output directories. It would be nice if NDepend was a little smarter about loading assemblies, but at least it has good error messages.
Even after resolving the version conflicts, I had trouble getting NDepend to load the console application from my solution. I had to manually drag-and-drop the exe into the assembly list, at which point it recognized it just fine.
The “Getting Started” experience is flexible and intuitive, but there are enough issues to make the process mildly frustrating for a first time user.
Running an analysis was surprisingly fast. Granted, I’m on a hefty workstation, but it still seemed blazingly fast considering what it was doing. The analysis generated an HTML report that included metrics, visualizations, graphs, tables, and the results of numerous CQL queries.
The HTML report is great for sharing the output of NDepend or for reviewing the analysis offline, but the NDepend tool itself enables you to interactively analyze your application. Be warned, though, that the default view can be overwhelming at first:
Even with high resolution monitors and the window maximized, this view is probably not going to be all that useful. Instead, you will likely find one of the configured alternative views more useful, such as the Dependency Matrix view:
I still found this view to be too cluttered, but like Visual Studio, NDepend’s UI is very customizable. However, unlike Visual Studio, it took a lot of trial and error to get things laid out the way I liked. The docking behavior seemed much more finicky than Visual Studio, and on multiple occasions attempting to pin/unpin an item would cause the layout to shift in unexpected ways. Even resizing the window caused strange behaviors at times. Still, after some massaging, I arrived at a less overwhelming layout:
One feature I’d like to see in NDepend is a “Save Custom View” command, that way I can save and restore my preferred layout for use in the future. Why is this feature important? Because it took me all of about 5 minutes to screw something up after getting my view the way I liked it, requiring me to “Reset Views” back to the default. 🙁
Overall, in my opinion the UI itself is the weakest area of NDepend. Yes, it’s functional, but there are some very noticeable usability problems here. I’m sure it is quite challenge to develop and maintain a UI that exposes all the capabilities of NDepend, but I think some additional work is warranted here.
While the UI might need some work, it doesn’t detract (too much) from what NDepend actually does really well, and that’s analyze your code base. The “Metrics” visualization gives you a map of sorts depicting your project by whatever metric you are interested in. Want to see your types by number of instructions?
How about your methods by lines of code?
Or by cyclomatic complexity?
I can also generate a nice map of my project dependencies (again, I can customize the visualization to emphasize different metrics):
These visualizations make it very easy to find areas of your project that warrant attention by simply glancing at the graphics. Unfortunately, the usability elephant raises his head here. A few things stick out worse than others. First, the behavior of the “Export to PNG” button is consistently inconsistent between the visualizations. On one view, the button brings up a dialog to save a snapshot to the file of your choosing. On another, it instantly exports the file and loads it up in Windows Media Viewer. I also had to make frequent use of the “Fit to Window” command on the Metrics visualization because I would accidentally click on the visualization, causing it to scroll unintentionally. These aren’t things that are going to turn someone off of using the tool, but they are still problems that should be addressed.
The rich visualizations make it easy to spot areas of your code base that need attention. While there are some usability problems here, they’re pretty minor and easy to overlook.
Code Query Language
The final piece that I want to talk about is CQL and the library of built-in constraints and checks that ship with NDepend. According to the website, there are 83 metrics available in CQL, and NDepend ships with queries to help you find potentially problematic areas quickly:
As you can see, this particular project has quite a few issues I might want to look into further. :) A cool feature of the CQL queries pane is that selecting one will update the “Metrics” visualization, with types matching the query highlighting blue as in the following screenshot:
This lets you quickly assess how wide-spread an issue is in your codebase. For details, you can use the CQL Query results window. Double-clicking an item in the results will open the corresponding location in your source code, so it’s very quick and easy to drill down from a CQL query to the underlying code.
One thing to note: many of the constraints that I checked were actually configured only to return the top 10 methods/types/whatever, so a constraint with a “10” next to it usually means “at least 10”. Keep that in mind as you are glancing through the constraints.
NDepend does seem to count properties as methods. While technically true (even auto properties are implemented as a pair of methods that access an automagically generated field), this can lead to unexpectedly high values for metrics such as “lack of cohesion” on types that expose many properties (such as view models in an ASP.NET MVC application).
There were a few things that I couldn’t figure out how to do (yet). For example, I wanted to build a CQL query to find all public methods that were part of a class marked with the NUnit TestFixture attribute who didn’t have a Test attribute applied to them. I suspect that there is a way to express this query, it just requires someone better with CQL than I am. 🙂
The built-in CQL queries can help you find trouble areas in your code base as well as determine how systemic a problem is. The syntax is clean and SQL-like. There are a few things that are difficult (at least for a novice) to express using the language, but the built-in queries are likely to cover 90% of what you would want to look at anyway.
Things I haven’t tried yet…
My review focused on the visual version of NDepend. NDepend also has a command-line version, an MSBuild task, and a NAnt task. There’s also an XLST transform for using NDepend output with CruiseControl.NET. Since NDepend generates a nice HTML report, it can easily be integrated into other CI servers as well, such as TeamCity.
NDepend also has Visual Studio and Reflector integration. While I use both tools, I did not (yet) test out the integration.
NDepend is a very deep tool with a lot of functionality. I feel like I’ve just scratched the surface. You will probably be hearing more about NDepend in the future as I continue to dig deeper into its capabilities.