Last time in this series, there was definitely some housekeeping to accomplish. I laid the groundwork for the series by talking a bit of theory — what are code metrics and what is static analysis? I also knocked out some more practical logistics such as taking you through how to get the code base I’m using as well as how to create and attach an NDepend project to it. The culmination was the creation of our very own, tiny, and relatively useless code metric (useless since NDepend already provides the metric we ‘created’).
So, seems like a good next thing to do is make the metric useful, but there may be an interim step in there of at least making it original. Let’s do that before we get to “useful.” But even before that, I’m going to do a bit of housekeeping and tell you about the NDepend feature of managing the queries and rules in the Queries and Rules Explorer.
Group Housekeeping
Last time around, I created the “My Rules” group under “Samples of Custom rules.” This was nice for illustrative purposes, but it’s not where I actually want it. I want to bring it up on the same level as that, right after “Defining JustMyCode”. To do that, you can simply drag it. Dragging it will result in a black bar indicating where it will wind up:
Once I’ve finished, it’ll be parked where I want it, as shown below. In the future, you can use this to move your groups around as you please. It’s pretty intuitive.
Now, have you noticed that this is called “My Rules” and that’s a little awkward, since we’re actually defining a query. We’re ultimately going to be trying to figure out how long it takes to comprehend a method, and that’s a query. A rule would be “it should take less than 30 seconds to comprehend a method.” We may play with making rules around this metric later, but for now, let’s give the group a more appropriate name. NDepend is integrated with the expected keyboard shortcuts, so you can fire away with the “rename” shortcut, which is F2. Do that while “My Rules” is highlighted, and you’ll get the standard rename behavior.
Let’s call it “My Metrics.”
Getting Units Right for Our Metric
Now, with various bits of housekeeping out of the way, let’s change the metric “Lines of Code” to be something else — something original. Open it in the Queries and Rules Editor, and change its name by changing the XML doc comment above the query within the “Name” tag. Let’s call it “Seconds to Comprehend a Method.” It’s important in these queries to specify the units in the name of the metric so that it’s clear upon inspection what, exactly, is being measured. The concept of units does not exist, per se, in NDepend so queries out of the box have titles like “# Source Files” and “# IL Instructions” to indicate that the unit is a count.
Now the title is looking good, but there’s a problem in the actual display of the metric on the side. Take a look:
It seems like a metric called “seconds to comprehend a method” probably shouldn’t internally report in terms of “# of lines of code (LOC)”. We probably want this to be “seconds.” The way you can accomplish this is by taking advantage of the fact that, under the covers, what we’re doing in this file is taking advantage of the C# construct of “anonymous type.”
In C#, an anonymous type is one that is defined even as it is instantiated, having its property names, types, and ordering declared in-situ. In an actual C# method, we might do something like:
1 |
var method = new { Name = "HardToUnderstand", Seconds = 4000 }; |
That’s not how things work in NDepend, however. For these queries and rules, we aren’t supplying declarations, per se, but rather returning an expression that the engine knows how to turn into graphical information at the bottom. In our example, currently, we’re returning an anonymous type consisting of the method itself as the first property, followed by its name and then its number of lines of code. This is translated in graphical format to what you see underneath the query editor automatically, with the values displayed as data and the property names as the headers. So, to change the header, we need to change the property name. Change this:
1 2 |
from m in JustMyCode.Methods select new { m, m.Name, m.NbLinesOfCode } |
to this:
1 2 |
from m in JustMyCode.Methods select new { m, m.Name, Seconds = m.NbLinesOfCode } |
and observe the new display results.
Fluent versus Query Linq
Finally, there’s one more thing that I’m going to do here before we wrap up this post. My strong preference over the years has been to use the fluent Linq syntax, rather than the query syntax, and based on what I see of the code written by others, I’m not alone. So, let’s do a conversion here before we get too much further.
1 2 |
from m in JustMyCode.Methods select new { m, m.Name, Seconds = m.NbLinesOfCode } |
This code can be expressed, equivalently, as
1 |
JustMyCode.Methods.Select(m => new { m, m.Name, Seconds = m.NbLinesOfCode }) |
Wrapping Up
So far, we’re taking it a little slow on making progress toward our killer, composite metric, but that’s somewhat by design. These posts split purpose between building a cool metric, and walking you through NDepend in some detail. In terms of the former goal, we went from having a metric that was just a repeat of one already supplied out of the box to one that is our own — at least at a casual inspection. Next time around, we’ll actually start doing something that doesn’t just assume it takes one second to comprehend each line of a method.
From a “getting to know NDepend” point of view, we took a walk through creating, renaming, and moving query/rule groups around, and we started to get into CQLinq a little bit in terms of practical application and theory. That’s a topic that will be visited more throughout the “Let’s Build a Metric” series, and one that we’ll pick right up with in the next post.
< Let’s Build a Metric 1: What’s in a Metric?
Comments:
Comments are closed.