NDepend

Improve your .NET code quality with NDepend

Software Rewrite: The Chase

Last week, a post I wrote, “The Myth of the Software Rewrite“, became pretty popular.  This generated a lot of comments and discussion, so I decided just to write a follow-up post to address the discussion, as opposed to typing a blog post’s worth of thoughts, distributed over 20 or 30 comments.  This is that post.

No Misconceptions

First of all, I want to be clear about what I’m talking about.  I’m specifically talking  about a situation where the prime, determining factor in whether or not to rewrite the software is that the development group has made a mess and is clamoring to rewrite it.  In essence, they’re declaring bankruptcy — “we’re in over our heads and need outside assistance to wipe the slate clean so we can have a fresh start.”  They’re telling the business and their stakeholders that the only path to joy is letting them start over.

Here are some situations that the article was not meant to address:

  • The business decides it wants a rewrite (which makes me skeptical, but I’m not addressing business decisions).
  • Piecemeal rewrite, a chunk at a time (because this is, in fact, what I would advocate).
  • A rewrite because the original made design assumptions that have become completely obsolete (e.g. designed around disk space being extremely expensive).
  • Rewriting the software to significantly expand or alter the offering (e.g. “we need to move from web to mobile devices and offer some new features, so let’s start fresh.”)

A Lesson From Joseph Heller

Joseph Heller is the author of one of my all time favorite works of fiction, Catch 22.  Even if you’ve never read this book, you’re probably familiar with the term from conversational reference.  A catch 22 is a paradoxical, no-win situation.  Consider an example from the book.

John Yossarian, the ‘protagonist,’ is an anti-heroic bombardier in World War II.  Among other character foibles, one is an intense desire not to participate in the war by flying missions.  He’d prefer to stay on the ground, where it’s safe.  To advance this interest, he attempts to convince an army doctor that he’s insane and thus not able to fly missions.  The army doctor responds with the eponymous catch 22:  “anyone who wants to get out of combat duty isn’t really crazy.”

If you take this to its logical conclusion, the only way that Yossarian could be too crazy to fly missions is if he actually wanted to fly missions.  And if he wanted to fly them, he wouldn’t be noteworthy and he wouldn’t be trying to get out of flying them in the first place.

I mention this vis a vis software rewrites for a simple reason.  The only team I would trust with a rewrite is a team that didn’t view rewriting the software as necessary or even preferable.

It’s the people who know how to manufacture small wins and who can inch back incrementally from the brink that I trust to start a codebase clean and keep it clean. People who view a periodic bankruptcy as “just the way it goes” are the people who are going to lead you to bankruptcy. Continue reading Software Rewrite: The Chase

Relax. Everyone’s Code Rots

I earn my living, or part of it, anyway, doing something very awkward.  I get called in to assess and analyze codebases for health and maintainability.  As you can no doubt imagine, this tends not to make me particularly popular with the folks who have constructed and who maintain this code.  “Who is this guy, and what does he know, anyway?” is a question that they ask, particularly when confronted with the parts of the assessment that paint the code in a less than flattering light.  And, frankly, they’re right to ask it.

But in reality, it’s not so much about who I am and what I know as it is about properties of code bases.  Are code elements, like types and methods, larger and more complex than those of the average code base?  Is there a high degree of coupling and a low degree of cohesion?  Are the portions of the code with the highest fan-in exercised by automated tests or are they extremely risky to change?  Are there volatile parts of the code base that are touched with every commit?  And, for all of these considerations and more, are they trending better or worse?

It’s this last question that is, perhaps, most important.  And it helps me answer the question, “who are you and what do you know?”  I’m a guy who has run these types of analyses on a lot of codebases and I can see how yours stacks up and where it’s going.  And where it’s going isn’t awesome — it’s rotting.

But I’ll come back to that point later. Continue reading Relax. Everyone’s Code Rots

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

Hidden Costs in Your Software

One of the things I remember most vividly from my CIO days was the RFP process for handling spikes in demands on my group’s time.  In case you haven’t participated in this on either side, the dance involves writing up a brief project description, sending it over to a handful of software consulting firms, and getting back tentative project proposals.  I’d pick one, and work would begin.

There were a lot more documents and legalese involved, but the gist, writ small, might be something like, “we need an application that will run in our data center, take information about customers out of our proprietary, and put it back into our CRM as notes, depending on a series of business rules.”  The response, in proposal form, would essentially be, “we’ll do that, and we think it’ll cost you about $30,000.”

This is what most people think of as the cost of a software project.  Perhaps it’s not a little, 5-figure line of business utility.  Perhaps it’s a $300,000 web or mobile application.  Perhaps it’s even a $30,000,000 enterprise workflow overhaul.  Whatever the case may be, there’s a tendency to think of software in terms of the cost of the labor necessary to write it.  The consulting firms would always base their proposals and estimates on a “blended rate” of the hourly cost of the labor.  Firms with in-house development staffs tend to reason about the cost of software projects as a function of the salaries of the folks tasked with the work.

Of course, if you’re a veteran at managing software projects and teams, you realize that there’s more to the total spend than just the cost of the labor.  No doubt you factor in the up-front and licensing cost of the tools you use to develop the software as well as the cost of the hardware on which it will eventually run.  You probably even factor in the cost of training users and operations folks, and paying maintenance programmers to keep the lights on.

But there are other, more subtle, hidden costs that I’d like to discuss — costs related to your approach to software development.  These are variable costs that depend on the nature of the code that your team is writing. Continue reading Hidden Costs in Your Software

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