Improve your .NET code quality with NDepend

Code Coverage Should Not Be a Management Concern

Code Coverage Should Not Be a Management Concern

You could easily find yourself mired in programmer debates over code coverage.  Here’s one, for instance.  It raged on for hundreds of votes, dozens of comments, many answers, and eight years before someone put it out to pasture as “opinion-based” and closed it.

Discussion participants debated a “reasonable” percentage of code coverage.  I imagine you can arrive at the right answer by taking the mean of all of the responses. (I’m just kidding.)

Some of the folks in that thread, however, declined to give a simple percentage.  Instead, they gave the obligatory consultant’s response of “it depends” or, in the case of the accepted answer, a parable.  I found it refreshing that not everybody picked some number between 50 and 100 and blurted it out.

But I found it interesting that certain questions went unasked.  What is the goal of this code coverage?  What problem does it solve?  And as for the reasonability of the number, reasonable to whom?

What is Code Coverage? (Briefly)

Before going any further, I’ll quickly explain the concept of code coverage for those not familiar, without belaboring the point.  Code coverage measures the percentage of code that your automated unit test suite executes when it runs.

So let’s say that you had a tiny codebase consisting of two methods with one line of code each.  If your unit test suite executed one method but not the other, you would have 50% code coverage.  In the real world, this becomes significantly more complicated.  In order to achieve total coverage, for instance, you must traverse all paths through control flow statements, such as if conditions, switch statements, and loops.

When people debate how much code coverage to have, they aren’t debating how “correct” the code should be.  Nor do they debate anything about the tests themselves, such as quantity or quality.  They’re simply asking how many lines of code per one hundred your test suite should cause to execute.

You can get tools that calculate this for you.  And you can also get tools that factor it into an overall code quality dashboard.

Continue reading Code Coverage Should Not Be a Management Concern

Is Your Team Wrong About Your Codebase? Prove It. Visually.

I don’t think I’ll shock anyone by pointing out that you can find plenty of disagreements among software developers.  Are singletons evil?  Is TDD a good idea (or dead)?  What’s the best IDE?  You can see this dynamic writ large across the internet.

But you can also see it writ small among teammates in software groups.  You’ve seen this before.  Individuals or small camps form around certain competing ideas, like how best to lay out the unit test suite or whether or not to use a certain design pattern. In healthy groups, these disagreements take the form of friendly banter or good-natured ribbing.  In less healthy groups, they create an us vs. them kind of dynamic and actual resentment.

I’ve experienced both flavors of this dynamic in my career.  Having to make concessions about how you do things is never fun, but group work requires it.  And so you live with the give-and-take of this in healthy groups.  But in an unhealthy group, frustration mounts with no benefit of positive collaboration to mitigate it.  This holds doubly true when one of the two sides has the decision-making authority or perhaps just writes a lot of the code and claims a form of squatter’s rights.

Status Quo Preservation

Division into camps can, of course, take many forms.  But I think the one you see most commonly happens when you have a group of developers or architects who have laid the ground rules for the codebase and then a disparate group of relative newcomers that want to change the status quo.

I once coined a term for a certain archetype in the world of software development: the expert beginner.  Expert beginners wind up in decision-making positions by default and then refuse to be swayed in the face of mounting evidence, third party opinions, or, well, really anything.  They dig in and convince themselves that they’re right about all matters relating to the codebase, and they express no interest in hearing dissenting opinions.  This commonly creates the toxic, adversarial dynamic here, and it leaves the rest of the group feeling helpless and frustrated.

Of course, this cuts the other way as well.  Sometimes the longest tenured decision makers of the group earned their position for good reason and acquit themselves well in defense of their positions.  Perhaps you shouldn’t adopt every passing fad and trend that comes along.  And these folks might find it tiresome to relitigate past architectural decisions ad nauseum every time a new developer hires on.  It probably doesn’t help when newbies throw around pejorative terms like “legacy code” and “the old way,” either.

Continue reading Is Your Team Wrong About Your Codebase? Prove It. Visually.

Code Quality Metrics: Separating the Signal from the Noise

Code Quality Metrics: Separating the Signal from the Noise

Say you’re working in some software development shop and you find yourself concerned with code quality metrics.  Reverse engineering your team’s path to this point isn’t terribly hard because, in all likelihood, one of two things happened.

First, it could be that the team underwhelmed someone, in some business sense — too many defects, serially missed deadlines, that sort of thing.  In response to that, leadership introduced a code quality initiative.  And you can’t improve on it if you can’t measure it.  For that reason, you found yourself googling “cyclomatic complexity” to see why the code you just wrote suddenly throws a warning.

The second option is internal motivation.  The team introduced the metrics of its own accord.  In this capacity, they serve as rumble strips on the side of your metaphorical road.  Doze off at the wheel a little, get a jolt, and correct course.

In either case, an odd sort of gulf emerges between the developers and the business.  And I think of this gulf as inherently noisy.

Code Quality Metrics for Developers

I spend a lot of time consulting with software shops.  And shops hiring consultants like me generally have code quality improvement initiatives underway.  As you can imagine, I see an awful lot of code metrics.

Here are some code quality metrics that I see tracked most commonly.  I don’t mean for this list to be an exhaustive one of all that I see.

  • Lines of code.  (This is an interesting one because, in aggregate, it’s often used to track progress.  But normalized over smaller granularities, like types and methods, people correlate it negatively with code quality — “that method is too big.”)
  • Cyclomatic complexity: the number of execution paths that exist through a given unit of code.  Less is more.
  • Unit test coverage: the percentage of paths through your code executed by your unit test suite.  More is more.
  • Static analysis tool/lint tool violations count: run a tool that provides automated code checks and then count the number of issues.

As software developers, we can easily understand these concepts and internalize them.  But to explain to the business why these matter requires either a good bit of effort or a “just trust us.”  After all, the business won’t understand these concepts as more than vague generalities.  There’s more testing coverage, or something…that sounds good, right?

These metrics can then have noise in them, meaning that how important they are for business outcomes becomes unclear.

Continue reading Code Quality Metrics: Separating the Signal from the Noise

C# Version History: Exploring the Language History from Past to Present

C# Version History: Examining the Language Past and Present

I still remember my first look at C# in the early 2000s.  Microsoft had released the first major version of the language.  I recall thinking that it was Java, except that Microsoft made it, called it something else, and put it into Visual Studio.  And I wasn’t alone in this sentiment.  In an old interview, Java inventor James Gosling called it an imitation.  “It’s sort of Java with reliability, productivity, and security deleted,” he said.  Ouch.

A lot changes in 15 years or so.  I doubt anyone would offer a similar assessment today.  In that time, Java has released four major language versions, while C# has released six.  The languages have charted divergent courses, and C# has seen a great deal of innovation.  Today, I’d like to take a look back on the history of C# and highlight some of those key points.

What did the language look like in its earliest incarnations?  And how has it evolved in the years since?

Continue reading C# Version History: Examining the Language Past and Present

What is static analysis?

What is Static Analysis? An Explanation for Everyone

Static analysis, as a concept, seems to earn itself a certain reputation.  The general population may regard programming as a technocratic, geeky pursuit.  But inside the world of programmers, static analysis has that equivalent rap.  It’s a geeky subject even among geeks.

I suspect this arises from the academic flavor to static analysis. You hear terms like “halting problem,” “satisfiability,” and “correctness proofs,” and you find yourself transported back to some 400-level discrete course from your undergrad.  And that’s assuming you did a CS undergrad.  If not, your eyes might glaze over.  Oh, and googling “static analysis” only to see things like this probably doesn’t help:

A static analysis screenshot that scares anyone looking at it

I have two CS degrees, concentrated heavily on the math side of things, and I specialize in static analysis. And that featured image makes my eyes glaze over.  So let’s hit the reset button here.  Let’s make the subject at least approachable and maybe, just maybe, even interesting.

Defining Static Analysis Dead Simply

Whether you’re a grizzled programming veteran, fresh out of a bootcamp, or can’t program a lick, you can understand the concept.  I’ll use an analogy first, to ease into things.

When you write software, you write instructions in a format that you and other programmers understand.  A program called the compiler (in many cases) then translates these into terms that computers understand and eventually into automation output.  So think of programming as writing a grocery list for a personal shopper.  You write down what you want, in easily understood terms.  The personal shopper then maps this list to his knowledge of the grocery store’s layout and eventually produces output in the form of food that he brings you.

What, then, is static analysis in this world?  Well, it’s analyzing the written grocery list itself and using it to speak to what the grocery shopping and groceries will be like.  For instance, you might say, “Wow, 140 watermelons, huh?  We’re going to need to rent a truck, so that’s going to cost you extra.”

When it comes to writing code, people usually reason about it by running it and seeing what happens.  In our world, that means the shopper simply takes the list, goes on the shopping trip, and sees how things go.  “Wow, this is a lot of watermelon,” he says as he fills the 15th cart full of the things.  Only then does he start to understand the ramifications of this.

Static analysis capitalizes on the fact that you can understand things about the upcoming grocery run without actually executing it.

Continue reading What is Static Analysis? An Explanation for Everyone

Should You Aim for 100 Percent Test Coverage?

Test coverage serves as one of the great lightning rods in the world of software development.  First, people ask whether it makes for a good metric at all.  Then they ask, if you want to use it as a metric, should you go for 100 percent coverage?  If not, what percentage should you go for? Maybe 42 percent, since that’s the meaning of life?

I don’t mean to trivialize an important discussion.  But sometimes it strikes me that this one could use some trivializing.  People dig in and draw battle lines over it, and counterproductive arguments often ensue.  It’s strange how fixated people get on this.

I’ll provide my take on the matter here, after a while.  But first, I’d like to offer a somewhat more philosophical look at the issue (hopefully without delving into overly abstract navel-gazing along the lines of “What even is a test, anyway, in the greater scheme of life?”)

What Does “Test Coverage” Measure?

First of all, let’s be very clear about what this metric measures.  Many in the debate — particularly those on the “less is more” side of it — quickly point out that test coverage does not measure the quality of the tests.  “You can have 100 percent coverage with completely worthless tests,” they’ll point out.  And they’ll be completely right.

To someone casually consuming this metric, the percentage can easily mislead.  After all, 100 percent coverage sounds an awful lot like 100 percent certainty.  If you hired me to do some work on your car and I told you that I’d done my work “with 100 percent coverage,” what would you assume?  I’m guessing you’d assume that I was 100 percent certain nothing would go wrong and that I invited you to be equally certain.  Critics of the total coverage school of thought point to this misunderstanding as a reason not to pursue that level of test coverage.  But personally, I just think it’s a reason to clarify definitions.

Continue reading Should You Aim for 100 Percent Test Coverage?

In Defense of Using Your Users as Software Testers

In most shops of any size, you’ll find a person that’s just a little too cynical.  I’m a little cynical myself, and we programmers tend to skew that way.  But this guy takes it one step further, often disparaging the company in ways that you think must be career-limiting.  And they probably are, but that’s his problem.

Think hard, and some man or woman you’ve worked with will come to mind.  Picture the person.  Let’s call him Cynical Chad. Now, imagine Chad saying, “Testing? That’s what our users are for!”  You’ve definitely heard someone say this at least once in your career.

This is an oh-so-clever way to imply that the company serially skimps on quality.  Maybe they’re always running behind a too-ambitious schedule.  Or perhaps they don’t like to spend the money on testing.  I’m sure Chad would be happy to regale you with tales of project manager and QA incompetence.  He’ll probably tell you about your own incompetence too, if you get a couple of beers in him.

But behind Chad’s casual maligning of your company lies a real phenomenon.  With their backs against the wall, companies will toss things into production, hope for the best, and rely on users to find defects.  If this didn’t happen with some regularity in the industry, it wouldn’t be fodder for Chad’s predictable jokes and complaints.

The Height of Unprofessionalism

Let’s now forget Chad.  He’s probably off somewhere telling everyone how clueless the VPs are, anyway.

Most of the groups that you’ll work with as a software pro would recoil in horror at a deliberate strategy of using your users as testers.  They work for months or years implementing the initial release and then subsequent features.  The company spends millions on their salaries and on the software.  So to toss it to the users and say “you find our mistakes” marks the height of unprofessionalism.  It’s sloppy.

Your pride and your organization’s professional reputation call for something else.  You build the software carefully, testing as you go.  You put it through the paces, not just with unit and acceptance tests, but with a whole suite of smoke tests, load tests, stress tests and endurance tests.  QA does exploratory testing.  And then, with all of that complete, you test it all again.

Only after all of this do you release it to the wild, hoping that defects will be rare.  The users receive a polished product of which you can be proud — not a rough draft to help you sort through.

Users as Testers Reconsidered

But before we simply accept that as the right answer and move on, let’s revisit the nature of these groups.  As I mentioned, the company spends millions of dollars building this software.  This involves hiring a team of experienced and proud professionals, among other things.  Significant time, money, and company stake go into this effort.

If you earn a living as a salaried software developer, your career will involve moving from one group like this to another.   In each of these situations, anything short of shipping a polished product smacks of failure.  And in each of these situations, you’ll encounter a Chad, accusing the company of just such a failure.

But what about other situations?  Should enlisting users as testers always mean a failure of due diligence?  Well, no, I would argue.  Sometimes it’s a perfectly sound business or life decision.

Continue reading In Defense of Using Your Users as Software Testers

How to Use NDepend’s Trend Charts

Imagine a scene for a moment.  A year earlier, a corporate VP spun up a major software project for his organization.  He brought a slew of his organization’s software developers into the project.  But he also needed to add more staff in the form of contractors.

This strained the budget, so he cut a few corners in terms of team member experience.  The VP reasoned that he could make up for this with strategic use of experienced architects up front.  Those architects would prototype good patterns and make it so the less seasoned contractors could just kind of paint by numbers.  The architects spent a few months doing just that and handed the work off to the contractors.

Fast forward to the present.  Now a consultant sits in a nice office, explaining to a beleaguered VP how they got so far behind schedule.  I can picture this scene quite easily because organizations hire me to be this consultant.  I live this scene over and over again.
Continue reading How to Use NDepend’s Trend Charts

Fixing Your Tangled Dependency Graph

I’ve written before about making use of NDepend’s dependency graph.  Well, indirectly, anyway.  In that post, I talked about the phenomenon of actual software architecture not matching the pretty diagrams people draw in Visio.  It reminds me of Helmuth von Moltke’s wisdom that no battle plan survives contact with the enemy.

Typically, architects conceive of wondrous, clean, and decoupled systems.  Then they immortalize this pristine architecture in Visio.  Naturally, print outs go up on the wall, and everyone knows what the system should look like.  But somehow, it never actually winds up looking like that. Continue reading Fixing Your Tangled Dependency Graph

Why NDepend Uses Google’s Page Rank

I remember my early days of blogging as sort of a comedy of errors.  Oh, don’t get me wrong.  I don’t think those early posts were terrible, since I’d always written a lot.  Rather, I knew very little about everything besides the writing.  For example, I initially thought link spammers were just somewhat daft blog commenters.  I stumbled through various mistakes and learned the art of blogging in fits and starts.  This included my discovery of something called page rank.

Page rank had a relatively involved calculation, but that didn’t interest me at the time.  Instead, I found myself dazzled by some gamification.  Sites like this one would take your domain and a captcha as input and spit out a score from 0 to 10 as output.  That simply, they turned my blogging world upside down.  I now had a score to chase and a means of comparing myself against others.  And I vaguely understood that getting more inbound links would increase my page rank score.

Of course, as an introvert, I struggle with outgoing self-promotion.  Cold outreach to people to see if they’d link to me never seriously occurred to me.  Instead, I reasoned that I would play the long game.  Write enough posts, and the shares start to come.  And then when the shares come, so too will the links.  So I watched my page rank inch slowly upward over time.

The Decline of Page Rank

My page rank ticked upward until one day it didn’t anymore.  Turns out, Google slowly killed it over the course of a number of years.  Ten months passed between its penultimate update and its final one.  So there I stood (metaphorically), waiting for a boost to my rank that would never come.

But why did Google kill page rank?  Wouldn’t such an easily digestible construct continue to help people?  Well, sort of.  Unfortunately, it disproportionately helped the wrong sort of people.

The Google founders developed the concept during their time at Stanford.  Conceptually, the page rank algorithm regards a link from site A to site B as a “vote” for site B, by site A.  But not all pages get to “vote” equally.  The higher a rank the page has, the more worthwhile its vote, creating a conceptual feedback loop.

On the surface, this sounds great, and, in many ways, it was.  As you can imagine, a site with a ton of inbound links, like a government study or a news outlet, would accumulate a great deal of rank.  Since employees would carefully curate such sites, you could put a lot of stock in a site to which they linked (and search engines did).  So in theory, you have a democratized system in which the sites best regarded by the public had the best rank.

But in this theory, no link spammers existed.  If you wanted good page rank, you could produce high quality, popular content.  Or you could pay some shady outfit to carpet bomb blog comment sections with links to your site.  Because of this fatal flaw, page rank eventually dwindled to obscurity.

A Useful Reappropriation of Page Rank

For clarity, understand that Google (probably) still uses some incarnation of this scheme.  But they no longer update the easily consumed public version of it.  They now use it as only one of many factors in what they display in response to searches.  The heyday of comparing page rank scores for sites has come and gone.  But that doesn’t mean we can’t use it elsewhere, and to great efficacy.

For instance, consider applying this to codebases.  Instead of a situation where website A links to website B, imagine a situation where type A refers directly to type B.  Now, imagine your codebase as a (hopefully acyclic) directed graph with edges and nodes.  You start to have an interesting vehicle for reasoning about your codebase.

What would a high rank mean in this context?  Well, relatively high rank for a type would mean that other types tended to refer to it at a high rate.  Types with relatively low (or zero) rank would take no dependencies, existing at the edge of your code.  And the types with the highest rank?  These would be types used by other types with high rank.

Continue reading Why NDepend Uses Google’s Page Rank