24 April 2014

NDepend to analyze F# code

Disclosure: Patrick Smacchia from NDepend kindly contacted me to offer an NDepend pro license for evaluation purposes.

If you’ve been active in the .NET world I’m pretty sure you’ve heard about NDepend before. It’s a pretty amazing code analysis tool that’s been kicking around for as long as I can remember – and I’m feeling pretty old today. It analyses IL code of one or more .NET assemblies and presents you with a very extensive range of metrics and graphics so you can “big data” the shit out of your code. If the predefined metrics are not enough for you, it also provides CQL (Code Query Language), which allows you to write custom analyses easily. Here’s an example:

warnif count > 0 from m in JustMyCode.Methods where m.NbLinesOfCode > 30
orderby m.NbLinesOfCode descending
select new { m, m.NbLinesOfCode, m.NbILInstructions }

This checks for methods that have more than 30 lines of code and orders them by number of code. Pretty straightforward, NDepend even comes with an IDE that gives you intellisense on writing these queries.

All good and well, and I’ve had some fun over the years using NDepend off and on. In my experience, while using it you always learn something about your or your team’s code. But often tools that work well with C# code have trouble with the different style of IL generated by F#. So how does NDepend deal with F# code? Let’s find out.

By the way, here’ s another post about NDepend applied to the F# compiler in case you want a second opinion.

For an initial impression with F#, I preferred using it on a project I know very well and that is also in the public domain. That doesn’t leave too many choices, obvious choice is of course FsCheck.

After choosing the projects to analyse I was greeted with the following screen:

image

Sure it looks pretty intimidating, but there’s a lot of useful stuff there. And the UI really helps you out a lot with hints and popups.

In the bottom right for example there’s a bunch of predefined CQL queries that are generating warnings. Some of them are a nice reassuring green. Some of them have some read there, which means NDepend thinks they are “critical”.

The one’s that highlighted is methods with too many parameters. I’m not too bothered with that – about half of them seem to be closures anyway. It’s easy to change the CQL to exclude methods with names that contain @ – that reduces it to two methods. One of them  is the constructor of a record type. Not really critical. Filtering that out generally seems a bit harder (though probably still doable), but I’ll move on.

In the “Dead code” category (dead code is one of my favourite low hanging fruits to improve a code base. So great to just delete code with impunity.) There were a lot of methods that are just being called by reflection because of FsCheck’s generator registration mechanism that’s based on type – all these are not concerning to me but NDepend is certainly fair in highlighting these. I also found a couple of closures again, I wasn’t so sure about these. Maybe the F# compiler is sometimes generating a closure class when it really isn’t needed?

One last area I’ll discuss is the Purity – Immutability – Side effects category. You’d hope that an F# project would not throw up too many issues there, and indeed FsCheck doesn’t. NDepend does find all the cases where I used an array (i.e. a mutable type) as part of an immutable record type. It flags those because such types give the false impression that the type is immutable while really the array is mutable. Of course I realized that when I used arrays, making a conscious decision to not mutate them anyway, but it’s a pretty powerful example of the kind of analysis that you can do in a handful of lines of CQL.

Conclusion

NDepend is a really powerful tool to analyse your code base. A short overview like this doesn’t really do it justice, and despite some of the smaller niggles I mentioned above it’s absolutely usable for F#. Really all of the analyses are built on CQL, giving you at once every opportunity to refine them to make them more applicable to your own code base, as well as a great set of examples to build your own.