Wednesday, April 6, 2011

Impressions of NDepend


I've been giving NDepend a go lately, in part because I've had my eye on it for a while, and in part because Patrick Smacchia offered me free trial of NDpedend Pro recently

I decided to try out NDpedend in a few different scenarios, that relate to different ways I might use it at work, so I spent a few hours with NDepend on three different code bases
  1. A small code base - ~3KLOC - that I know quite well because I wrote 80% of it.
  2. A medium sized code base - ~70KLOC - that I also know well because I worked on the team that wrote. But I only wrote a small portion of it myself.
  3. A small code base - ~5KLOC - that I don't know at all. -I've only had a 10 minute intro to the architecture.

These, IMHO, span a number of scenarios where I might use NDepend: From scenarios where I know the code well, but want NDepend to help keeping myself and my team in check, to scenarios where I am reviewing or taking over an unknown code base, and want NDepend to help me get an overview and to help me drill into problematic areas.

Ok, but lets back up a bit: What is NDepend? -NDepend is a static analysis tool for .NET code that provides metrics like cyclomatic complexity, average and max methods per class, average and max statements per method, assembly dependencies, namespace dependencies and so on. Check the NDepend site for the full feature list.
And what does the pro version offer? -The pro version is an interactive version of the free NDepend. The free version will spit out a report with all the metrics in them, for you to look at, but the pro version integrates with Visual Studio to give you the possiblity to drill into the data, and to modify the metics using the so-called Code Query Language - CQL.

My observations in general from running NDepend on the three code bases listed above:

  • NDepend is pretty fast, at least when the code bases are not too big. This is less important if you intend only to run NDepend on your CI server as a late stage step, but if you want to take an interactive approach it's crucial.
  • The interactive drill down capabilities of the pro version are enticing...is that good or bad?...for me, on the one hand, it meant that I actually discovered more about the code bases than I think I otherwise would have, on the other hand, I also spent more time than I planned to.
  • The default NDepend analysis is expressed in CQL queries that can be modified in Visual Studio, which I used to tighten some of the metrics. Doing that was dead easy, and is a real benefit because it allows you to go with your own standards.
  • The default warning levels for the different metrics are, in my opinion, not tight enough. I especially want fewer statements per method and lower cyclomatic complexity. So that's sometihng I be tweaking in future uses of NDepend.

My observations relating specifically to the three code base above are:

  1. NDepend did not tell me anything I did not know about this code base. -But it's also a degenerate case becasue the code base is so small and because I wrote most of it myself, so I have all it in my head anyway.
  2. This case is a lot more interesting: The code base is of a size where it is hard to hold it all in your head, and it was written by a team, so no one person has actually looked deeply at all the code. For this code base NDepend gave me some interesting insights:
    • NDepend was able to produce a very sensible list of methods and classes that need refactoring. About half of them I was aware already, but the other half I wasn't.
    • NDepend was also able to pin point to major areas where the problematic code was concentrated. I sort of knew those were pain points, but NDepend made it a lot clearer. That's a big win.
    • NDepend quickly produced a complete dependency graph, with a half hour of moving boxes around, deleting irrelavant boxes and so on I had a useful diagram of the dependencies in the project. That was actually something we had wanted for a while, but hadn't gotten around to, so that was a nice by-product.
  3. The third code base was another small one, but one I didn't know. In this case NDepend gave me:
    • A quick overview of the internal and external dependencies. Again in a fairly clear and readable diagram that the teams tech lead was able to confirm quickly
    • Pinpointed the two methods that very overly complex (2 aren't many BTW - that team did a good job, so far)
    • A single instance of a cyclic namespace dependency - that the teams tech lead wasn't aware of
To sum it's been very easy to get up and running with NDepend, and the tools has provided valuable insights in two of three cases. Considering that the first case was small and written mostly by me, it's not big deal that NDepend didn't tell me anything new in that case (in fact it would have been sort of a big deal if it had - I should know those things already). I recommend giving NDepend a go, I know will be using it routinely in the future for code bases I work on and for code bases I review.

Monday, March 14, 2011

Why Commit Comments Matter

Lets look at something pretty basic: Commit comments. Why are they important? -Good commit comments should summarize the context and intent of the commit. Writing good commit comments gives you a better version history and gives you better individual commits. Lets look at each of these claims in turn.

Better Version History
Good commit comments makes the version history better in a number of ways:

  • Having commit comments that summarize intent turns the commit history of the previous day into a quick way for team members to check what happened in the code base yesterday - and they can readily drill down into the code diffs if they want.
  • Having commit comments that summarizes the context of the commit - e.g. by including a bug report number or a user story id - is a very simple and flexible way to introduce traceability from code to requirements.  
  • Having commit comments that summarize the context and the intent is an excellent tool for understanding code later on: When something seems to work, but also seems a bit odd, it is great to be able do an svn blame or git blame and get an idea of the context and intent behind that code.

Better Individual Commits
Writing good commit comments requires just a little bit more thought than writing no comment or writing a non-comment like "checking in code" or "bugfixes" or "I'm going home now". That little bit of extra thought is quite often just enough to make you realize if your commit could break that other part over there, or that you haven't run all the relevant tests, or that it just isn't one cohesive whole and should be split into two or three individual commits. That last point can also lead you to committing more often, and as a result synching and integrating with the rest of the team more often. Good cycle.

But I'm In a Hurry
Yeah, well we all are. So don't waste teammates time by breaking the build or having them read through the version history diff by diff just so you save a commit comment. Besides writing good commit comments really doesn't take long. Seriously we're talking 10 seconds. Just pick a format and stick to it. I like
<task id>: <Main intent>. <Important technicalities>
 That's quick to write, right?

Friday, February 25, 2011

Testable C# or C# TUFs and TUCs


Re-reading Michael Feathers nice article on "Testable Java" I decided to see how the same thing looks in C#. Now, Java and C# aren't too far a part, so the difference isn't huge.

The "Testable Java" article gives a simple rule for how we can write code that is friendly to unit tests. -As the article points out the rule is superflous if we follow TDD stricly. But - being human - we don't always do that. Sometimes we write only integration tests or even acceptance tests here and now, and postposne unit tests. Sometimes we skip the automated tests altogether. In these cases it's an advantage to have code that is at least friendly to unit tests. If so, it's afordable to add the unit tests later.

Feathers' rule is:
"Never hide a TUF within a TUC"
and Feathers goes on to define TUF as a "Test Unfriendly Feature" and TUC as a "Test Unfriendly Construct". Now TUFs are things that we want to mock out in many unit tests, but TUCs are language constructs that are hard to substitute for testing.

TUFs

Examles, from the article,  of TUFs:

  •   Database access
  •   File system access
  •   Network access
  •   Access to side effecting APIs
  •   Long running computations
  •   Inscrutable computations
  •   Static variable usage

The first three are basically I/O, and in general I/O is test unfriendly because it is slow, and usually assumes things about the outside world - like "the webservice is reachable" or "the robot arm is connected through the serial port".
The next - side effects - is about avoiding tests that changes something and annoys somebody.
Long running computations are a nuisance, and will make you skip test runs.
Inscrutable computations, are things that are just plain hard to understand - maybe due the "clever" code-smell or to essential complexity.
These TUFs are all TUFs in .NET as well.

TUCs

The article lists a number of Java TUCs. This is my ported list of C# TUCs:

  • Sealed classes
  • Static methods
  • Private methods
  • Static initializers
  • Constructors
  • Static constructors 
  • New expressions

 and these are few more C# TUCs IMHO:

  • Non-virtual methods
  • Internal methods
  • Internal classes  

The point is to remember - even when you skip the TDD strictness - that testability is an important part of maintainability. So if maintainability is quality attribute you want, then keep an eye on the testability. If not, those TUFs inside of TUCs will come back and bite you.

Oh, and the other point: Go read Michael Feathers' article. It's well worth it.