Analyzing Code with NDepend
Disclaimer: A long time ago, in a galaxy far away, I helped coordinate the Indy Code Camp. We gave away a few donated copies of NDepend as prizes, and while setting that up, Patrick Smacchia offered me a license if I’d be willing to write about my NDepend experiences on my blog. Having heard about NDepend in the past, I happily took him up on it – making sure it was clear that I would write about my experience regardless of whether they were positive or negative. So this is a “sponsored” post, in that I received an NDepend license, but the license donation did not purchase any of the content of this post.
An astute reader will probably look at the date that I helped with the Indy Code Camp and compare it to the date of this post, and figure out that it was about two years ago that Patrick asked me to evaluate NDepend. And I’m not so happy to say that in those two years, I really didn’t use it. But recently I have more time available to me for doing specifically this sort of thing.
I think Scott Hanselman summed up the initial NDepend experience quite well.
Like PowerShell, the first 10 minutes of NDepend is the hardest. It has to click first. There’s the whole "what the hell am I looking at" process, often followed by the "screw this" declaration, followed by a quick uninstallation and a sense of "what happened."
I’m not going to do a comprehensive overview like Scott or others have done – at this point I just can’t do that as I’m still in kind of the “what the hell is this” phase. But it’s slowly beginning to click. For me, two things that click and help me continue on and work to understand this application.
One, I know I need the information NDepend can give me. I may not understand it all immediately, but I’ve been deep in the code of some applications long enough to see (and write) the good, the bad, and the ugly. I need ways to root out the bad and ugly, without having to dive into all the code in-depth. I also need metrics to help show that the good really is good. Especially when you’re working on a team of several people, each with varying opinions and each who writes their own flavor of code. Just because I don’t like someone else’s code doesn’t mean it’s bad code. Metrics can help me separate my aesthetic or organizational concerns from real problems or smells. And then I can make them write it my way anyway. 😉
Two, and more fun than the first is NDepend’s Code Query Language or CQL. In my opinion, this is an easy “hook” to get someone to look closer at NDepend and get past that 10-minute hump. I have seen a developer’s face literally light up when they hear what CQL can do, especially if they’ve done any work with a database and SQL in the past.
NDepend’s website has the best documentation of CQL, even if the docs feel overwhelming at first. There’s also some information about embedding CQL into your code as in-line constraints that NDepend can enforce during your build, though as others have mentioned it’s not a practical solution.
Of immediate interest to me, due to something I’m doing at work, is catching breaking API changes that might accidentally happen during a maintenance release. Patrick covers how to do this here. But as an example, let’s analyze the breaking API changes in StructureMap between version 2.5.4 and 2.6.1.
Note: I got confused at first, because I put both versions of StructureMap into the same directory and renamed the files to include the version number. NDepend didn’t like this and flagged every single method as removed and added. I’m not sure what I did wrong, but it took a bit to figure out, and it sucks for situations where a version number (or a name change) might cause an assembly name not to match, even though it’s functionally the same.
The first thing to do is select the two assemblies to compare – here I’m choosing StructureMap 2.5.4 on the left, and 2.6.1 on the right.
After the NDepend project has been created, I can press ALT+Q to bring up the CQL editor, and enter the following query:
WARN IF Count > 0 IN SELECT METHODS WHERE
IsInOlderBuild AND IsPublic AND (VisibilityWasChanged OR WasRemoved)
It reads pretty well, especially if you’re familiar with SQL. Literally it’s “warn me if methods exist that were in the older build, were public, and the visibility has changed or the method was removed.”
You can see below, 5 methods were “removed” from StructureMap’s public API – in this case, they are literally removed (and not just made internal or private). That means that upgrading from 2.5.4 to 2.6.1 could mean you have to change or recompile your code.
Likewise you can see that no public types were removed, thus no breaking change exists and the CQL query isn’t flagged as a warning.
This is some powerful stuff, and as I begin to incorporate it more and more into my daily workflow I’ll post about how I’m using it.
The newest version supports a console runner, a stand-alone GUI, and full integration into Visual Studio 2005, 2008, and 2010. For small projects that can exist within a single Visual Studio solution, it’s perfect. For larger projects that span multiple solutions, NDepend still allows you to analyze a set of assemblies, the UI is just embedded inside Visual Studio – and the integration is pretty usable for me so far.