I’m ashamed to admit it, but over three months ago (in late August 2008 to be exact!), I was contacted by Patrick Smacchia who is (among other things) the author of the NDepend software metrics reporting and analysis tool. Patrick asked if I would take a look at the product in its recent incarnation, evaluate it, and maybe post some of my comments on my blog for others to see and (I’m sure) help raise the awareness of NDepend among some of my regular readers (and the Internet at-large thanks to Larry and Sergey over at the Big-G).
Excuses, Excuses, Excuses: I’m Embarrassed
Then things got a little nuts at work, the work on the Summer of NHibernate series spiraled out of control from the originally-planned five installments to the final 15 parts it ended up including, and I generally lost all track of my commitment to him. But it was always in the back of my mind that I’d made a commitment and it bothered me that I never managed to follow through for him. He reached out to me as a fellow developer, I offered to take a look, and then I did…nothing
The Internet ‘Promises vs Action’ Deficit
I’m sure Patrick’s gotten commitments from all kinds of people to review his software; because of the anonymity-factor, promises on the Internet are a dime-a-dozen. And probably, just as the number of people who download my screencasts vs. actually contributed even a token amount of money is waaaaay out of whack, probably so too is the number of people who actually investigated NDepend and posted anything about it for him. But I was determined not to be one of the negative statistics for his efforts to publicize his work on NDepend and so I made a pact with myself that — no matter what — I would somehow manage to review NDepend before the end of 2008. And by my count, it looks like I made it with about 30 hours to spare — at least for me on the East Coast of the United States!
NDepend: If You Have a Question About Your Code, it Will Answer it For You!
If you cannot tell from the title of this post, I think that what Patrick has done with NDepend is absolutely incredible. Really. And I don’t offer such praise for things that don’t completely blow me away; the world is full of mediocre software and it certainly doesn’t need me to help sell any of the crapware out there.
But NDepend is absolutely wonderful to work with. It somehow manages to put a tremendous wealth of information about your codebase at your fingertips and yet also provide intuitive navigation, drill-down, drill-up (?), and move-sideways capabilities that just make sense — and all of this in a neat, pleasant, informative-but-not-overwhelming windowed UI.
If you haven’t heard of NDepend before, then you’re in for a treat. And if you have heard of NDepend but haven’t looked at it since its 1.x days (or maybe never thought to dig into it in any detail), then do yourself a favor and get reacquainted with it — it bears nearly no resemblance to its former self (except perhaps loosely in that some of the charts and graphs still look kind of the same even if they have entirely different navigation paradigms within them now). I looked at the product some years back in its 1.x days and that’s partly why I (stupidly and somewhat lazily) took so long to do this review — “What could have changed that much since 1.x?“, I figured. Pretty much everything, it turns out.
What the Heck is NDepend?
Well, from the homepage comes this…
NDepend is a tool that simplifies managing a complex .NET code base. Architects and developers can analyze code structure, specify design rules, plan massive refactoring, do effective code reviews and master evolution by comparing different versions of the code.
The result is better communication, improved quality, easier maintenance and faster development.
…which kind of gets the ball rolling, but really doesn’t do it justice.
- analyzes your compiled assemblies (and leverages the PDB files — if you have them — to lead back to the source code)
- can use binaries, Visual Studio Solutions, or Project files as analysis sources to get rolling
- reports on compliance with many, many pre-canned metrics (cyclomatic complexity, efferent/afferent coupling, SLOC, etc.)
- displays the analysis of these metrics using easy-to-grok charts, graphs, lists, and other data visualization elements
- allows the easy navigation from any one graphic depiction of a data element to just about any other graphic depiction of a data element by a simple mouse-click (and — thank god! — allows easy navigation back to the prior data element using a familiar browser-like back-button that’s nearly always present)
- offers a very powerful SQL-like query language (CQL, or Code-Query-Language) that can be used to literally query your codebase (and these queries can be saved and re-used again and again) — the pre-canned provided metrics themselves are actually just pre-defined CQL expressions that you can open up, review, tear apart, or do anything else you want to with them!
- integrates with all the other code-analysis and review tools you know and love like Reflector for MSIL dissasembly, NCover for unit test coverage, CruiseControl.NET for continuous integration, and more
- allows you to actually compare two sets of analysis results to see if the trending over time is in the right direction
So How does it Work?
NDepend is really two separate programs: NDepend.Console.exe that does the actual analysis work to spit out an XML report of the results of the analysis (and also compose it and some static PNG files into an HTML report that you can view in your browser) and VisualNDepend.exe that provides for the UI to evaluate and interactively navigate the results. In a CI environment, you would be concerned with the console application and its resulting XML and HTML content, but in an interactive situation, you want to begin and end with the truly awesome VisualNDepend windows application.
As an example, let’s take a project that my company has been working on for the past six-plus years (project and client to remain anonymous). I selected this project to run through the analysis gauntlet for a few reasons:
- its code that was started by another company, we took it over six years ago and had to retain A LOT of legacy code in there (no budget for a re-write, much as we might have enjoyed the opportunity)
- its had no fewer than four different development teams working on it over the years so there’s plenty of conflicting ’styles’ in the code
- its been ported from .NET 1.1 (well, technically from 1.0 to 1.1) to .NET 2.0 so its got some oddities from that process too
- its a winforms app that had its architecture set some years ago so there’s lots of horrible practices in there to show up in an analysis
- its got dependencies on a number of 3rd-party libraries (GIS mapping components, scanner driver components, etc.)
- its got a feature set that has evolved considerably over the years (both additive and subtractive) so there’s bound to be some fun things left over in there that aren’t even in use at all any more
- its got exactly ZERO unit tests (a fact I’m not proud of at all) but IT WORKS has been the benchmark for the work on the app
- in short, this project is bound to be a complete mess — in fact I’m counting on it! — but its a mess that WORKS for the client so we leave it and continue to tinker around the edges since they won’t pay for the appropriate face-lift at a code level (I’m sure we can all relate to clients like that~!)
Setting Up the Project
The first thing that we need to do is setup the NDepend project itself. The NDepend project is a ‘unit-of-work’ (essentially a collection of the binaries that we are trying to analyze and the settings that we want to use) that we can save and load just like any other document or project in any other software.
In my case, I took the lazy-man’s way out and just used the ‘Add Assemblies of a VisualStudio Solution’ button to select the .sln file for the code that I want to analyze. And why not — the solution file contains everything I need to analyze including all of my own code and all of the other dependent referenced assemblies so its the easiest thing to do.
Then I simply hit F5 (just like the Run-With-Debugger default key binding in Visual Studio — get it?) to run the analysis and I’m off to the races.
Without any effort at all, VisualNDepend launches my browser and loads the pre-defined HTML version of the analysis results. This is a preconfigured HTML page that displays all of the metrics from the analysis in a simple, readable HTML report format.
While non-interactive, this report actually contains every bit of information that we will (eventually) navigate through in the VisualNDepend interface. It even contains some PNG files that are dynamically generated to display some graphs and charts in addition to the more tabular data shown at right.
After I close the browser, VisualNDepend reminds me that there are updated analysis results that can be loaded into it for review with this helpful dialog box shown at left. This is just another example of low-friction application design: it knows what I’m likely to want to do next, so it makes it easy for me to do so without requiring me to click FILE –> OPEN and then browse to some report file to get the results into the viewer.
What you cannot see in the screenshot at right is that when I load the analysis results into VisualNDepend, it starts with a HELP window slid up covering the lower portion of the UI (you can see the HELP tab docked to the bottom of the window in the screeenshot). The HELP system is open to ‘Common Tasks’ making getting started with Visual NDepend very easy even for the inexperienced. The UI for VisualNDepend makes extensive use of the DXperience winforms UI controls (from my friends at DevExpress who make the CodeRush/Refactor tools upon which I rely heavily — just a coincidence, I swear!) to provide a VisualStudio-like experience with dockable tool windows, pin-able sliding tabs, and other UI paradigms that any VisualStudio user will feel quite at home interacting with.
The one thing that you can really get a sense of from the screenshot at right is how important it is to have a decent-sized monitor upon which to run VisualNDepend . That screenshot is about 1024×768 (picked so that the image wasn’t so incredibly huge that nobody could see/download it from my blog) but I don’t really recommend anyone do real work (with VisualNDepend or otherwise) on anything that isn’t larger than SVGA resolution (that’s 1024×768 for you under-30 crowd that grew up after the death of CGA, EGA and VGA ).
However, as the screenshot at left demonstrates, if you hit the ‘pin’ icon in the titlebar of any one of the multiple windows, that window will temporarily maximize to fill the available area — making it really at least passably useable on even an SVGA monitor. I think all things considered, this is about the best way to handle this kind of issue in the design of the UI and it points out again the care and consideration that went into making an intuitive and usable interface for the application.
To further improve your ability to perform common analysis tasks with VisualNDepend, as shown in the screenshot at right is the VIEW menu with its six preset window layouts to select from as needed. Interested in digging into what the dependency matrix says about your code? Set the View layout to ‘Views to Work with Dependency Matrix’. Again, somebody (Patrick!) was thinking hard here about how to make such an information-rich environment remain on the good side of ‘completely overwhelming’.
So what does it tell me?
Let’s start by inspecting one of the easiest to understand pre-canned metrics (recall that all metrics are just pre-defined CQL expressions, so we can always change them, create our own, etc. as needed).
In the screenshot at left, I have setup the view for ‘Views to Work with Metrics’ and selected the ‘Types should not have too many responsibilities’ constraint. What you are seeing is an example of how the entire UI is completely interrelated and dynamically updates to reflect changing context.
The large window full of ‘blobs’ shows the entire solution displayed for me in a graphical manner where the size of each blob represents the relative count of lines of code in the element. This (like nearly everything in NDepend) is completely customizable — in this case by the drop-down control at the top of the window that would let me select just about anything else I’d like the relative size of the blob-chart (sure it has a better-sounding actual name ) to represent.
In the left-hand pane of the display we see the results of the CQL query: the 10 classes at the top of the ‘too many responsibilities list’. The location of each of these within each assembly in the solution is highlighted in blue in the blob-graph, showing me exactly where the trouble lies.
Want to know how the CQL determines when too much responsibility is too much? Click ‘Edit Query’ to show exactly what’s going on. Here’s content of the Edit Query window for this CQL constraint…
// <Name>Type should not have too many responsabilities (Efferent Coupling)</Name> WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE TypeCe > 50 ORDER BY TypeCe DESC // The Efferent Coupling (TypeCe) for a particular type is the number of types // it directly depends on. Notice that types declared in tier assemblies are taken into account. // Types that depends on too many others type (more than 50) are complex and have // more than one responsability. They are good candidate for refactoring. // More information available in this article: // http://codebetter.com/blogs/patricksmacchia/archive/2008/02/15/code-metrics-on-coupling-dead-code-design-flaws-and-re-engineering.aspx
Amazingly, not only do I get the actual CQL query to see for myself what’s going on, but I get comments that describe the intent of the query, an explanation as to why I should care about conforming my code to the constraint, and a hyperlink to a blog post describing the whole thing in more detail! This whole product is full of this kind of stuff — incredibly detailed, comprehensive, well-thought-out, highly-structured information.
And since this query (and all the others) are all just CQL I can inspect, edit, and tweak for myself, if I’d rather see the top 20 classes where this is a problem in my code, I can just change this right here in the query and re-apply the query to my code to see the new results.
I could go on for a lot longer, but who the heck wants to read my gushing over how far Patrick has managed to take this thing since its 1.x days? Suffice it to say that I have a new favorite code-analyzer and I will be spending some time running some of my company’s other projects through this same wringer to see where we are designing ourselves into a deep, dark hole from which we can never emerge successful.
There’s all kinds of other valuable capabilities in the full NDepend product and Patrick has got some great detailed content on all this and more on the NDepend website (including video tutorials, walk-throughs, testimonials and more) so head on over there, download a trial, check it out for yourself, and then buy a copy or two for your shop — at least for yourself if even part of your job (as mine does) involves your being responsible for code quality.
And even if you don’t want to use NDepend as an automated code-quality policeman, consider its other uses too including but not limited to…
- client wants you to commit to supporting a project developed by someone else (prior consultants, etc.) and you want to know how good (or bad!) their work was so that you can decide how much to charge the client — wish I had done this before we’d taken over the project I just analyzed for this blog post; I’d have radically changed our cost estimate for certain~!
- client wants you to tell them how long it will take to add feature X to the existing codebase; using NDepend you can immediately see how much the rest of the code is dependent on the class(es) you will have to change — and how much what you’re considering changing is dependent on the rest of the class(es)
For these reasons and more, if you’re a shop that is doing anything non-trivial in .NET, I cannot recommend a better product for your team than NDepend — go get a copy now and start cringing at the results of its analysis of your work .