This version of the site is now archived. See the next iteration at v4.chriskrycho.com.

Two (absurd) anti-patterns

A pair of anti-patterns I’ve run into recently in my software development work, both of which are absolutely awful, though in completely different (and quite distinct) ways. I thought I’d share The Empty If and Wash, Rinse, Repeat, just so the world can share a bit of my pain.

The Empty “if”

This is the smaller and more trivial of the two, but I see it frequently in certain parts of the code base I’m working on.

if (someVar == 0 && someOtherVar == 0) {
    // do nothing
} else {
    someFunction(someVar, someOtherVar);
    // ... lots of other things
}

Of course, as anyone who’s spent any time thinking about this can see, there’s a much more elegant solution:

if (someVar != 0 || someOtherVar != 0) {
    someFunction(someVar, someOtherVar);
    // ... lots of other things
}

In fact, you can even go a step further! Without losing a hint of clarity, you can write it like this:1

if (someVar || someOtherVar) {
    someFunction(someVar, someOtherVar);
    // ... lots of other things
}

Why this pattern is so common, I have no idea. But common it is.

The takeaway: think about your logic setup so you don’t end up with empty blocks. Gladly, most compilers these days (and any I’m using!) are smart enough that those things usually get optimized away. As I’ve said before, program for people, not computers.

Wash, Rinse, Repeat

I was working on one set of related programs recently, each of which performs a similar task. Most of the code hasn’t been touched in quite some time—anywhere from a year to, in a few cases, a decade or more—so it needed to be rebuilt with our current toolchain. I took the opportunity to clean up the code a little—no functional changes, but running an auto-formatter over it to match current code style, and then cleaning up deprecated code that had been commented out, etc.

As I worked through this set of about a dozen executables, I soon discovered that they had been constructed as follows:

  1. Find a program that does something similar to what we want to do with this program.
  2. Copy the contents of that program over in a new source file wholesale.
  3. Make a couple changes so that it reads and writes different files on the file system and accounts for some small differences in the formatting of those files.
  4. Build.
  5. Release.

Note that, across these dozen or so programs, each of which was approximately 250–300 lines long when I was done cleaning it up, at least fully one half of the code was duplicated. As a result, there are roughly 1400 lines of extra code to maintain, that could all be extracted into a common module—probably in a library—that all of these other pieces could link against. Indeed, where possible in other parts of this software package, I’ve made precisely that move.

The takeaway here is fairly simple. Don’t use copy and paste. (I’ve said this before, too.) If, as a programmer, you find yourself using copy and paste, you should take a step back and reevaluate your approach; there is almost certainly a better—as in, more maintainable, less work for everyone in the medium and certainly in the long term—way of doing whatever it is you’re doing. Extract common behavior into common functions. Don’t repeat yourself.


  1. Thanks to Montana Rowe for flagging a silly mistake I’d made here.

Discussion

  • Your final example shown below only works in a language like C/C++ where the language interprets someVar/someOtherVar being zero as false:

    if (someVar || someOtherVar) {
        someFunction(someVar, someOtherVar);
        // ... lots of other things
    }

    Meaning in a language like java, that is not a valid evaluation with int type, so you would have to use your example which is more explicit and in some ways more readable for clarity:

    if (someVar != 0 || someOtherVar != 0) {
        someFunction(someVar, someOtherVar);
        // ... lots of other things
    }

    :-D

    Offer a rejoinder↓
    • That’s true. However, for my purposes (that is: all the language I’m working in, e.g. C, C++, Javascript, PHP, and Python) it does the trick. It’s particularly Pythonic:

      if someVar or someOtherVar:
          someFunction(someVar, someOtherVar)
          # ... lots of other things
      Offer a rejoinder↓
  • Eric Dorbin thought to say:

    I’m not really a programmer, but I know enough programming to feel your pain. I’m a little suprised you see this so much in professional code, these are rookie methods that should be eliminated from one’s repertoire once a better way is learned. Personally, I always got a giddy feeling whenever I found a way to simplify/condense/streamline things like you did here.

    Offer a rejoinder↓
    • Well, you see, that’s the problem, actually: my predecessor was, erm, distinctly not a professional programmer (though he did it for a long time, he never wanted to learn how to do it well… so he never did it well). And it’s painful. I get the same satisfaction, but it starts to grate after the 300th time.

      Offer a rejoinder↓
  • Eric Dorbin thought to say:

    Ah, yes, I suppose not everyone possesses the passion for learning and for doing things excellently. I totally understand how that would be frustrating for you too. When I talk of feeling giddy, I mean more when I was writing my own code and found ways of doing it better. Compensating for the same mistake of someone else many times can certainly become tedious.

    Offer a rejoinder↓

Your rejoinder to David

Opt for silence instead↑

Anonymity is most unhelpful. Please identify yourself!

You may use GitHub-flavored Markdown and/or these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>