Improve your .NET code quality with NDepend

Let’s Build a Metric: Wrapping Up

In the penultimate post in the metrics series, I explained the reasoning for winding down this series.  I also talked about performing one last experiment.  Well, that last experiment is in the books, and I’m going to share the results here, today.  The idea was to see what progress so far looked like, when applied to real code bases.

Before we get to the results, let’s recap the (admittedly quite incomplete) experimental formula that we’ve arrived at thus far.


T is the time in seconds, and it is a function of p, the number of parameters; n, the number of logical lines of code; f, the number of class fields; and, g, the number of globals.  Let’s see how this stacks up to reality.

I picked the methods to look at basically just by poking around at random C# projects on GitHub.  I tried to look for methods that were not overly jargon intensive and that minimized the factors that are not accounted for by this formula.

Continue reading Let’s Build a Metric: Wrapping Up

Let’s Build a Metric Reconsidered

If you’ve been keeping track, you’ll noticed that it’s been a while since the last post in this series.  In case you’d forgotten or lost track, the primary goal is to build a composite metric experimentally.  I’ve been looking to work experimentally toward a “time to comprehend” metric.  The series also has a secondary goal, which is to take a tour of NDepend and see how it and static analysis in general work.

To lay my cards on the table, the reason I haven’t picked the series back up is a data-based one.  Simply put, not a lot of people read them, and the readership has waned since the beginning of the series.  On the bright side, the experiment has attracted a small, loyal following of people that participate in the code experiments, but that seems to be about it for the audience.  I’ve mulled over the reasoning for these posts not doing as well as the other posts I make to the blog, but, at the end of the day, the data is the data, and my main interest is providing the readership with material that interests you.

Because of this, I’m going to draw the series to a close before I had originally intended to do so.  Don’t worry — I’m not just going to abruptly call it a day.  Rather, I’m going to take the progress that we have made and turn it into a rough stab at a tentative, composite metric.  From there, I’ll call for one last experiment to see how that metric does.

Continue reading Let’s Build a Metric Reconsidered

Let’s Build a Metric: Global and Local Scope

Last time in this series, I began an exploration of how a method might be impacted by the scope of the variables that it uses.  The idea is that it’s easier to comprehend a method that uses more narrowly scoped variables.  If method A uses nothing but local variables, method B uses class level fields, and method C uses global state, time to comprehend will increase from A to B to C.  Let’s introduce this hypothesis into the running experiment for a time to comprehend metric.

But before we can do that, let’s take a look at how those concepts are represented in NDepend.  Let’s simplify the query we used last time and use that as a starting point.  This is a query that simply looks at the fields used somewhere in a method.

Recall the Board constructor we were looking at last time.

The constructor uses two class-level fields: _boardSize and _pieces. If we run this query in the query editor, we see that there are two fields. But, here’s another cool feature of NDepend — you can actually drill into that field to see what the fields in question are. Here’s what that looks like.


That’s good progress. We can address the “class field” part of the equation when we start adding this consideration to our metric. But what about global state? Well, let’s see what happens to FieldsUsed if we add a global field. I added a little global variable repository to the code base and then amended the constructor to use it.

Now when I run NDepend’s analysis, I see that there are 3 fields, and it lists the field from GlobalDumpingGround. This is good news, but not unexpected. After all, there’s nothing in the naming of “FieldsUsed” to suggest that it’s only talking about fields for that method’s class. So now we have a small task of figuring out how to distinguish local fields from global variables.

This might seem very simple, but there is a bit of subtlety to it. It isn’t just a matter of “fields from this class versus from others.” After all, I could have an instance field from some other class that’s visible to my method. You don’t see this a lot because standard practice is to have fields be private, but it is possible. This means that we need to put qualifiers on both types of field for our experimental purposes here. Let’s take a look at that.

For local fields, we’re going to look at fields that share a parent type with the method, meaning they belong to the class in question. We also want them not to be publicly visible, to capture the general usage practice of encapsulation. For global fields, we want them to be publicly visible and static, since this is essentially the definition of global scope.

When we apply this to the board constructor, the results are what we expect: 2 local fields and 1 global.


That’s perfectly fine and good, but what about properties? Working with a local or global property is probably no different when it comes to time to comprehend, and this query will fail to take properties into account. Let’s add those and see what things look like.

Here’s the revised code:

The constructor now worries about a global variable, a global property, 2 local fields, and a local property. So let’s make an update to the query we’re running.

And, finally, let’s see what NDepend tells us.


We still have two local fields and one global field. But we now have a local property being accessed here. That’s not a surprise, since we’re initializing the Pieces array with the local property Size. But why are there 2 global properties when the only one we’re dealing with is AGlobalProperty? Well, that’s a tricky bit, and it’s occurring because even though we reason about AGlobalProperty as a single variable, it’s actually two methods as far as the IL is concerned: a getter and a setter. And, we’re using both of them.

And that brings me to an explanation of the CQLinq here. I’m searching for methods, because that’s what properties are under the hood. Specifically, I’m searching for locals as getters and setters that share a parent type with the calling method. And for globals, I’m just looking for getter/setter methods that are publicly visible and static. I don’t care what the parent type is — a global is a global.

There are, of course, a lot of refinements and different ways we could spin these queries. When reasoning about a problematic global state, we might say that we don’t care about public statics that are only readable, because the mutability is what creates the problem. When applying this sort of querying to your code base, you may do just that.

But for the purposes of the experiment, what I’m interested in is mainly the effect of these scopes on readability. Now that you’ve seen a primer on the way the concepts can be quantified, stay tuned for another round of experimentation.

Let’s Build a Metric: Using CQLinq to Reason about Application State

I’ve been letting the experiments run for a bit before posting results so as to give all participants enough time to submit, if they so choose.  So, I’ll refresh everyone’s memory a bit here.  Last time, I published a study of how long it took, in seconds (self reported) for readers to comprehend a series of methods that varied by lines of code.  (Gist here).  The result was that comprehension appears to vary roughly quadratically with the number of logical lines of code.  The results of the next study are now ready, and they’re interesting!

Off the cuff, I fully expected cyclomatic complexity to drive up comprehension time faster than the number of lines of code.  It turns out, however, that this isn’t the case.  Here is a graph of the results of people’s time to comprehend code that varied only by cyclomatic complexity.  (Gist here).


If you look at the shape of this graph, the increase is slightly more aggressive than linear, but not nearly as aggressive as the increase that comes with an increase in lines of code.  When you account for the fact that a control flow statement is also a line of code, it actually appears that conditionals are easier to comprehend than the mathematical statements from the first experiment.

Because of this finding, I’m going to ignore cyclomatic complexity for the time being in our rough cut time to comprehend metrics.  I’ll assume that control flow statements impact time to comprehend as lines of code more than as conditional branching scenarios.  Perhaps this makes sense, too, since understanding all of the branching of a method is probably an easier task than testing all paths through it.

As an aside, one of the things I love about NDepend is that it lets me be relatively scientific about the approach to code.  I constantly have questions about the character and makeup of code, and NDepend provides a great framework for getting answers quickly.  I’ve actually parlayed this into a nice component of my consulting work — doing professional assessments of code bases and looking for gaps that can be assessed.

Going back to our in-progress metric, it’s going to be important to start reasoning about other factors that pertain to methods.  Here are a couple of the original hypotheses from earlier in the series that we could explore next.

  • Understanding methods that refer to class fields take longer than purely functional methods.
  • Time to comprehend is dramatically increased by reference to global variables/state.

If I turn a critical eye to these predictions, there are two key components: scope and popularity.  By scope, I mean, “how closely to the method is this thing defined?”  Is it a local variable, defined right there in the method?  Is it a class field that I have to scroll up to find a definition of?  Is it defined in some other file somewhere (or even some other assembly)?  One would assume that having to pause reading the method, navigate to some other file, open it, and read to find the definition of a variable would mean a sharp spike in time to comprehend versus an integer declared on the first line of the method.

And, by popularity, I mean, how hard is it to reason about the state of the member in question?  If you have a class with a field and two methods that use it, it’s pretty easy to understand the relationship and what the field’s value is likely to be.  If we’re talking about a global variable, then it quickly becomes almost unknowable what the thing might be and when.  You have to suck the entirety of the application’s behavior into your head to understand all the things that might happen in your method.

I’m not going to boil that ocean here, but I am going to introduce a few lesser known bits of awesomeness that come along for the ride in CQLinq.  Take a look at the following CQLinq.

If your reaction is anything like mine the first time I encountered this, you’re probably thinking, “you can do THAT?!” Yep, you sure can. Here’s what it looks like against a specific method in my Chess TDD code base.


The constructor highlighted above is shown here:


As you can see, it has one parameter, uses two fields, and assigns both of those fields.

When you simply browse through the out of the box metrics that come with NDepend, these are not the kind of things you notice immediately.  The things toward which most people gravitate are obvious metrics, like method size, cyclomatic complexity, and test coverage.  But, under the hood, in the world of CQLinq, there are so many more questions that you can answer about a code base.

Stay tuned for next time, as we start exploring them in more detail and looking at how we can validate potential hypotheses about impact on time to comprehend.

And if you want to take part in this on going experiment, click below to sign up.

Join the Experiment

Let’s Build a Metric: Incorporating Results and Exploring CQLinq

It turns out I was wrong in the last post, at least if the early returns from the second experiment are to be believed.  Luckily, the scientific method allows for wrongness and is even so kind as to provide a means for correcting it.  I hypothesized that time to comprehend would vary at a higher order with cyclomatic complexity than with lines of code.  This appears not to be the case.  Hey, that’s why we are running the experiments, right?

By the way, as always, you can join the experiment if you want.
You don’t need to have participated from the beginning by any stretch, and you can opt in or out for any given experiment as suits your schedule.

Join the Experiment


Results of the First Experiment

Recall that the first experiment asked people to record time to comprehend for a series of methods that varied by number of lines of code.  To keep the signal to noise ratio as high as possible, the methods were simply sequential arithmetic operations, operating on an input and eventually returning a transformed output.  There were no local variables or class level fields, no control flow statements, no method invocations, and no reaching into global state.  Here is a graph of the results from doing this on 3 methods, with 1, 5, and 10 logical lines of code.


So as not to overburden anyone with work, and because it’s still early, the experiment contained three methods, yielding three points.  Because this looked loosely quadratic, I used the three points to generate a quadratic formula, which turned out to be this.


It’s far from perfect, but this gives us our first crack at shaping time to comprehend as something experimental, rather than purely hypothetical.  Let’s take a look at how to do this using NDepend in Visual Studio.  Recall all the way back in the second post in this series that I defined a metric for time to comprehend.  It was essentially a placeholder for the concept, pending experimental results.

All we’re doing is setting the unit we’ve defined, “Seconds,” equal to the number of lines of code in a method.  But hey, now that we’ve got some actual data, let’s go with it!  The code for this metric now looks like this.

I’ve spread on multiple lines for the sake of readability and with a nod to the notion that this will grow as time goes by. Also to note is that I’ve included, for now, the number of logical lines of code as a handy reference point.

Exploring CQLinq Functionality

This is all fine, but it’s a little hard to read.  As long as we’re here, let’s do a brief foray into NDepend’s functionality.  I’m talking specifically about CQLinq syntax.  If you’re going to get as much mileage as humanly possible out of this tool, you need to become familiar with CQLinq.  It’s what will let you define your own custom ways of looking at and reasoning about your code.

I’ve  made no secret that I prefer fluent/expression Linq syntax over the operator syntax, but there are times when the former isn’t your best bet.  This is one of those times, because I want to take advantage of the “let” keyword to define some things up front for readability.  Here’s the metric converted to the operator syntax.

With that in place, let’s get rid of the cumbersome repetition of “m.NbLinesOfCode” by using the let keyword. And, while we’re at it, let’s give NbLinesOfCode a different name. Here’s what that looks like in CQLinq.

That looks a lot more readable, huh? It’s now something at least resembling the equation pictured above. But there are a few more tweaks we can make here to really clean this thing up, and they just so happen to demonstrate slightly more advanced CQLinq functionality. We’ll use the let keyword to define a function instead of a simple assignment, and then we’ll expand the names out a bit to boot. Here’s the result.

Pretty darned readable, if I do say so myself! It’s particularly nice the way seconds is now expressed — as a function of our LengthFactor equation. As we incorporate more results, this approach will allow this thing to scale better with readability, as you’ll be able to see how each consideration contributes to the seconds.

So, what does it look like? Check it out.

Updated Seconds Metric with CQLinq

Now we can examine the code base and get a nice readout of our (extremely rudimentary) calculation of how long a given method will take to understand.  And you know what else is cool?  The data points of 8.6 seconds for the 1 LLOC method and 51 for the 5 LLOC method.  Those are cool because those were the experimental averages, and seeing them in the IDE means that I did the math right. 🙂

So we finally have some experimental progress and there’s some good learning about CQLinq here.  Stay tuned for next time!




Let’s Build a Metric 7: Counting the Inputs

Over the last two Let’s Build a Metric installments of this series, I’ve talked about different ways to count lines of code and about ways to count different paths through your code. So far, I’ve offered up the hypotheses that more statements/lines in a method means more time to comprehend, and that more paths through the code mean more time to comprehend. I’ll further offer the hypothesis that comprehension time varies more strongly with complexity than it does with lines of code.

I do have results in for the first hypothesis, but will hold off for one more installment before posting those. Everyone on the mailing list will soon receive the second experiment, around complexity, so I’ll post the results there in an installment or two, when I circle back to modifying the composite metric. If you haven’t yet signed up for the experiment, please do so here.

Join the Experiment

More Parameters Means Harder to Read?

In this post, I’d like to address another consideration that I hypothesize will directly correlate with time to comprehend a method: parameter count. Now, unlike these last two posts, parameter count offers no hidden surprises. Unlike lines of code, I don’t know of several different ways that one might approach counting method parameters, and unlike cyclomatic complexity, there’s no slick term for this that involves exponential growth vectors. This is just a matter of tabulating the number of arguments to your methods.

Instead of offering some cool new fact for geek water-cooler trivia, I’ll offer a relatively strong opinion about method parameters. Don’t have a lot of them. In fact, don’t have more than 3, and even 3 is pushing it. Do I have your attention? Good. Continue reading Let’s Build a Metric 7: Counting the Inputs

Let’s Build a Metric 6: Cyclomatic Complexity Explained

In the last installment of this series, I talked a good bit about lines of code. As it turns out, the question, “what is a line of code?” is actually more complex than it first appears.  Of the three different ways I mentioned to regard a line of code, I settled on “logical lines of code” as the one to use as part of assessing time to comprehend.

As promised, I sent code to use as part of the experiment, and got some responses. So, thanks to everyone who participated. If you’d like to sign up for the experiment, but have yet to do so, please feel free to click below.

Join the Experiment

Here is the code that went out for consideration. I’m not posting the results yet so that people can still submit without any anchoring effect and also because I’m not, in this installment, going to be updating the composite metric just yet.

The reason that I’m discussing this code is to show how simple it was. I mean, really, look at this code and think of all that’s missing.

  • There are no control flow statements.
  • There are no field accesses.
  • There is no interaction with collaborators.
  • There is no interaction with global state.
  • There is no internal scoping of any kind.

These are purely functional methods that take an integer as input, do things to it using local declarations, and then return it as output.  And via this approach, we’ve fired the first tracer bullet at isolating logical lines of code in a method.  So let’s set that aside for now and fire another one at an orthogonal concern.

Before, I talked about the meaning of a line of code.  Now I’d like to talk about the meaning of complexity in your methods.  Specifically here, I’m referring to what’s called “cyclomatic complexity.”  Cyclomatic complexity is a measure of the number of path’s through a piece of source code.  Let’s see a few examples to get the hang of it.

Consider the following method from the Pawn class in the Chess TDD codebase.

This method has a cyclomatic complexity of 1 because there is only one path through the code. Contrast that with the following method from the Board class.

The cyclomatic complexity of this method is 2 because there are two paths through it.

  1. The if condition evaluates to true and the method throws an exception.
  2. The if condition evaluates to false and the method finishes executing.

Be mindful that “if” isn’t the only way to create multiple paths through the code.  For instance, this method also has a cyclomatic complexity of 2 because of the ternary operator creating two different execution paths.

Cyclomatic complexity can increase quite rapidly, particularly when nested conditionals enter the equation. This method has a cyclomatic complexity of 4, and you can see it already is starting to get hard to figure out exactly why.

Imagine what it starts to look like as methods have things like large degrees of nesting, switch statements, and conditional after conditional. The cyclomatic complexity can soar to the point where it’s unlikely that every path through the code has even ever been executed, let alone tested.

So it stands to reason that something pretty simple to articulate, like complexity, can have a nuanced effect on the time to comprehend a code base. In the upcoming installment of our experiments, I’d like to focus on cyclomatic complexity and its effect on method time to comprehend.

But I’ll close out this post by offering up a video showing you one of the ways that NDepend allows you to browse around your code by cyclomatic complexity.


 Let’s Build a Metric 7: Counting the Inputs >

< Let’s Build a Metric 5: Flavors of Lines of Code

Let’s Build a Metric 5: Flavors of Lines of Code

The last episode of this series was heavy on theory, so let’s balance it out a bit with some applied science. The lofty goal of this series of posts is to construct a way to predict the time to comprehend a method. But, regardless of how that turns out and how close we get, we’re going to take a detailed look at NDepend, static analysis, and code metrics along the way.

One of the simplest hypotheses from the last post was, “the more statements there are in a method, the longer it will take to comprehend.” Intuitively, this makes sense. The more stuff there is in a method, the longer it will take to grok. But you’ll notice that I said “statement” rather than “line of code.” What did I mean by that? Are these things interchangeable? Continue reading Let’s Build a Metric 5: Flavors of Lines of Code

Let’s Build a Metric 4: Science and Experiments

Last time around, I promised a foray into Newtonian mechanics, so I might as well start with that.  This is the equation for gravitational force, one of the 4 fundamental forces of nature.


To put it conversationally, the force of gravity between two objects is the product of the mass of each object, divided by the square of the distance between the objects, multiplied by some thing called “G”.  Really, I’m not kidding about the last bit.  “G” is the “gravitational constant” and just a placeholder thrown in to make the rest of the math work out.

What Newton figured out was the relationship between the variables at play when it comes to gravitation: the two masses and the distance between them.  The heavier the masses, the more gravitation, but if you started moving the masses apart, the force dropped off precipitously.  He figured out that the force of gravity varied proportionally with the mass of each object and varied inversely with the square of the distance.  As far as Newton was concerned, the law of gravitation, specifically about the Earth, would have been expressed as follows.


This formula — this expression of proportionality — demonstrates that it is possible to understand relationships via experimentation, without being able to fully express reality in the form of a neat equation that always works out.  Newton stuck a value in there, called the graviational constant, and called it a day.  Some 70 years or so after Newton died, a man named Henry Cavendish was able to perform an experiment and empirically determine the value of G, resulting in a pretty accurate equation (notwithstanding general relativity).

Code Readability Mechanics

Okay, so what does this have to do with our mission here, to work toward a metric for method readability?  Well, it demonstrates that we can shave off thin slices of this thing for reasoning purposes, without having to go right away for the whole enchilada.  Think of experiments that Newton, had he been the size of solar system, might have run.

He could have placed two planets a million miles apart, recorded the force between them, increased the number to 2 and then 3 million miles, and recorded what had happened to the force of gravity.  This would have told him nothing apart from the fact that the force of gravity was inversely proportional to the square of the distance.  He could have placed two planets a million miles apart, and then swapped out one planet for others that were half and twice the size of the original.  This would have told him only that the force was linearly proportional to the mass of the planet he was swapping out.  He then might have swapped a rocky planet for a gas planet of equal mass and observed that that particular variance was irrelevant.

And then, following each experiment, he could have used each piece of learning, in sequence, to build the equation one piece at a time.   It stands to reason that we can, and probably should, do the same thing with the approach to creating a “time to read/comprehend” metric.

So what are some things that would lengthen the time to comprehend a method?  It’s brain storming time.  I’m going to put some ideas out there, but please feel free to chime in with more in the comments.  For me, it boils down to thinking of the degenerative cases and expanding outward from there.  The simplest method to understand would be a no-op, probably followed by simple getters and setters.  So, thinking inductively, where do we get stuck?

Here are some hypotheses that I have.  These all refer to the gestalt of comprehension.  What I mean is you may be able to find a particular method that serves as a counter-example, but I’m hypothesizing that over a large sample size, these will hold up.

  • The more statements there are in a method, the longer it will take to comprehend.
  • Simple variable assignment has very little effect on time to comprehend.
  • Assignment using arrays and other collection types has more effect than simple assignment.
  • Control flow statements are harder to comprehend than assignments.
  • Compound boolean conditions substantially increase time to comprehend.
  • Naming of helper methods means the difference between extremely large time to comprehend (poorly named helper method) and nearly trivial (well named).
  • Understanding methods that refer to class fields take longer than purely functional methods.
  • Collaborators with poorly named methods sharply increase time to comprehend.
  • Collaborators with well named methods are roughly equivalent to assignment and commands.
  • Time to comprehend is dramatically increased by reference to global variables/state.

From this list, we can extract some things that would need to be measured.  Think of Newton with his hypotheses about mass, distance, and gas/rocky; he’d need a way to measure each of those properties so that he could vary them and observe the results.  Same thing here.  Given this list of hypotheses, here are some things that we’d have to be able to observe/count/measure.

  • Count statements in a method.
  • Identify simple assignment.
  • Identify array/collection assignment.
  • Identify and count control flow statements.
  • Count conditions inside of a boolean expression.
  • Poorly named versus well named members (this is probably going to be pretty hard).
  • Identify and count class field references.
  • Identify methods that refer to no class state.
  • Identify method references to global state.


There’s been a very science-y theme to this post.  I started off with Newtonian mechanics and then formed some hypotheses about what makes code take a long time to comprehend.  From those hypotheses, I extracted things that would need to be observed and measured to start trying to confirm them.  So, in accordance with the scientific method, the next thing to do is to start running some experiments.  In the next post, I’m going to show you how to use NDepend to actually make the observations I’ve outlined.

In parallel with that, I’d like to invite you to sign up to help me with running experiments in time to comprehend.  I don’t mind using myself as the guinea pig for these experiments, but the more data, the better the result.  As this series goes on, it’d be great if you could help by supplying your time to comprehend for some methods. Click below if you’re interested in signing up.

Join the Experiment

The landing page explains in more detail, but participation is pretty low impact.  We’ll periodically send out code to read, and you just read it and record how long it took you to understand it.  So, if you’re interested and you’re up for reading a little code, please join me!


< Let’s Build a Metric 3: Compositeness

Let’s Build a Metric 5: Flavors of Lines of Code >

Let’s Build a Metric 3: Compositeness

Last time, I talked through a little bit of housekeeping on the way to creating a metric that would be, uniquely, ours.  Nevermind the fact that, under the hood, the metric is still lines of code.  It now has a promising name and is expressed in the units we want.  And, I think that’s okay.  There is a lot of functionality and ground to cover in NDepend, so a steady, measurable pace makes sense.

It’s now time to start thinking about the nature of the metric to be created here, which is essentially a measure of time.  That’s pretty ambitious because it contains two components: defining a composite metric (recall that this is a mathematical transform on measured properties) and then tying it an observed outcome via experimentation.  In this series, I’m not assuming that anyone reading has much advanced knowledge about static analysis and metrics, so let’s get you to the point where you grok a composite metric.  We’ll tackle the experimentation a little later.

A Look at a Composite Metric

I could walk you through creating a second query under the “My Metrics” group that we created, but I also want this to be an opportunity to explore NDepend’s rich feature set.  So instead of that, navigate to NDpened->Metric->Code Quality->Types with Poor Cohesion.


When you do that, you’re going to see a metric much more complicated than the one we defined in the “Queries and Rules Edit” window.  Here’s the code for it, comments and all.

There’s a good bit to process here.  The CQLinq code here is inspecting Types and providing data on Types.  “Type” here means any class or struct in your code base (well, okay, in my code base), along with a warning if you see anything that matches.  And, what does matching mean?  Well, looking at the compound conditional statement, a type matches if it has “LCOM” greater than .8 or “LCOMHS” greater than .95 and it also has more than 10 fields and 10 methods.  So, to recap, poor cohesion means that there are a good number of fields, a good number of methods, and… something… for these acronyms.

LCOM stands for “Lack [of] Cohesion of Methods.”  If you look up cohesion in the dictionary, you’ll find the second definition particularly suited for this conversation: “cohering or tending to cohere; well-integrated; unified.”  We’d say that a type is “cohesive” if it is unified in purpose or, to borrow from the annals of clean code, if it conforms to the single responsibility principle.  To get a little more concrete, consider an extremely cohesive class.

This class is extremely cohesive.  It has one field and three methods, and every method in the class operates on the field.  Type cohesion might be described as “how close do you get to every method operating on every field?”

Now, here’s the crux of our challenge in defining a composite metric: how do you take that anecdotal, qualitative description, and put a number to it?  How do you get from “wow, Recipe is pretty cohesive” to 0.0?

Well, this is where the mathematical transform part comes in.  Here is how NDepend calculates Lack of Cohesion of Methods (LCOM).

  • LCOM = 1 – (SUM(MF)/(M*F))


  • M is the number of methods in class (both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods).
  • F is the number of instance fields in the class.
  • MF is the number of methods of the class accessing a particular instance field.
  • Sum(MF) is the sum of MF over all instance fields of the class.

Quantifying the Qualitative

Whoah.  Okay, let’s walk before we run.  It’ll be helpful to work backward from an already proposed formula.  What do we know by looking at this?

Well, at the very highest level, we’re talking about fields and methods in the class, and how they interact.  It’s easy enough to count the number of methods and fields — so far, so good.  MF, for a given field, the number of methods in the class that access that field, which means that Sum(MF) is the aggregate for all fields.  Sum(MF) will therefore be less than or equal to M*F.  They’re only equal in the case where every method accesses every field.

Thus the term SUM(MF)/(M*F) will range from 0 to 1, which means that the value of this metric ranges from 1 to 0.  1 is thus a perfectly non-cohesive class and 0 is a perfectly cohesive class.  Notice that I described Recipe as “0.0”?  If you run this metric on that class, you’ll see that it scores 0 for a “perfect cohesion score.”  And so, the goal here becomes obvious.  The creator of this metric wanted to come up with a way to describe cohesion normalized between 0 and 1 with a concept of bounded, “perfect” endpoints.

And this is the essence of compositeness, though to build such a metric, you create the transform rather than working backward to deduce the reasoning.  You start out with a qualitative evaluation and then think about a hypothesis for how you want to represent that data.  Is there a minimum?  A maximum?  Should the curve between them be linear?  Exponential?  Logarithmic?

It’s not a trivial line of thinking, by any stretch.  As it turns out, there isn’t even agreement, per se, on the best way to describe type cohesion.  You’ll notice that NDepend supports a secondary metric (that I intentionally omitted from the formula definition above for simplicity) for cohesion called LCOM HS, which stands for the “Henderson Sellers Lack of Cohesion of Methods.”  This is a slightly different algorithm for computing cohesion.  And man, if experts in the field can’t agree on the ideal metric, you can see that this is a tall order.  But hey, I didn’t say it’d be easy — just fun.

So, having seen a little bit more of NDepend and established a foundation for understanding a bit of the theory behind composite code metrics, I’ll leave off until next time, when I’ll dig a bit into how we can start reasoning about our own composite metric for “time to understand a method.”  Stay tuned because that will get interesting — I’ll go through a little bit more of NDepend and even get into Newtonian Mechanics a little.  But not too far.  I promise.

< Let’s Build a Metric 2: Getting the Units Right

Let’s Build a Metric 4: Science and Experiments >