Okay, this is one I’ve been meaning to write for far too long. (So long, in fact, that NDepend 3 is released already, and has been for some time now.) One of the indispensable tools I use is NDepend. This is a great code analysis tool, providing not only valuable insight into our code base, but also visualization tools that let me easily convey a sense of architectural issues to management. Whenever I need to understand why something isn’t working the way I think it should, or I get the dreaded “cannot add this reference because of a circular dependency” message, my first stop is NDepend.
To give you some idea of the scale, I work daily with a solution that runs about 110 projects, and around 600KLoC. (There’s more than that in the solution, but most of the rest involves reporting.) One of the things I like about NDepend is that it has a “metrics view” that lets you easily see the relative size of the pieces of the application. What I can’t show easily is that, when you mouse over the boxes, you get more details about the contents of that box. In the image below, the red text gives details about a specific method with 3 lines of code. The two projects on the left are UI projects, and they account for a pretty large proportion of the code.
I use the “dependency” view quite often. It’s a little scary at first, since it can generate a diagram that looks like this:
However, once I remove all of the system libraries and third-party libraries, it gets more reasonable (rotated for space reasons):
I know, I know…. “more reasonable?!?!” We have several applications in that solution. It’s a simple enough matter to exclude all but the stack for one application. Things get much better then. (This is far more legible on my monitor, full-size…. a guy has to have some secrets!)
Even with the default arrangement of the projects, you can see that there are architectural layers in the application. (Yes, it looks like they’re less than clean, and there is some of that. However, some of the ugliness is caused by cross-cutting concerns and DTOs.) To help figure out what’s going on, NDepend has a cool feature called “CQL”. Essentially, this is a query language written against the analysis data. For example, there’s a canned query for “Top Methods to Refactor”. Clicking on that and dialing the number of results up to 100 (the default is 10), yields the following picture:
What’s really awesome about the CQL queries is that the results are highlighted on the Metrics view, as shown here. Each class is organized into a large rectangle with smaller rectangles showing the individual methods. So, the partial graph at left shows that the top 100 methods that are prime refactoring candidates belong to just 4 classes. A more cynical person than I might even suggest that these same classes might be the causes of a fair number of bugs, since the most complex code is going to be in these classes.
A feature I don’t use often gives the ability to compare versions of code, so you could actually see how this code changes over time – hopefully, it would get more maintainable.
Another interesting way to visualize your dependencies is, appropriately, the “Dependency Matrix.” Patrick Smacchia (C# MVP and creator of NDepend) has written great articles on his blog (here’s one on NDepend 3, and another on using the dependency graphs to identify patterns) on how to interpret these, so I won’t belabor that topic.
Essentially, this is a graph of all of the dependencies within your code, either at the project, class or method level. (Although, truth be told, I find the project level most useful, unless I’m trying to find the specific class or method that has caused the architectural intent to be violated.)
At the moment, all this goodness is a stand-alone app … but I’ll soon be upgrading to NDepend 3, which has tight integration with Visual Studio. I can hardly wait to see just how cool that is!