Is “Defensive Programming” actually healthy?

I can’t solve this one, and I think I need your help. So, a developer was responding to a code review comment I made and they simply asked me, “why would I do that?” I gave my standard, dusty answer: “because you have to code defensively— you don’t know what the future holds.” But I suddenly realized… am I proliferating a fear of the future? How could I code fearfully when I run where I blog so often about living happily in the present? I’ll share the specific code example with you. I’m hoping to hear from the community whether my solution is “coding in the moment” or if I am actually bowing down to the fear.

A classic defensive programming example

Part of the duty of reviewing a coworkers code is to try and see what they might have missed. This follows the standard definition of defensive programming:

Defensive programming is when a programmer anticipates problems and writes code to deal with them. (1)

So, imagine you were reviewing a pull request and the code was making some assumptions. At first glance, the code sample below looks innocuous. And maybe it is. But having spent decades fixing other people’s production bugs, my spider-sense was tingly with fear. A specific bug comes to mind (which I’ll be demonstrating it in the second coding sample below) which leaves me staring at the Github code review not knowing how to proceed. I’m trapped wondering if I should keep quiet to preserve a carefree relationship with my peer or if I should speak up and prevent the potential production bug. Am I being haunted by the early years of my career where I was relegated to only bug fixing? Or were my formative years an invaluable training ground that makes me who I am today?

“If you are caught in sorrow and regret about the past, or if you are anxious about what will happen to you in the future, then you are not really free to enjoy the many wonders of life that are available in the here and now.”

~ Thich Nhat Hanh

See for yourself if you can find where a bug can easily manifest. If you can’t see the bug, then I’m almost jealous that your past didn’t inform you of the potential nightmare:

Okay, yea. No problems “in the present.” And one could argue (as my peer continues to do so) that since our program is only used in geographical regions that are limited to the three major traffic signals (red, yellow, and green) that we don’t have to worry about this right now. My peer is using one of my favorite phrases against me: “You Ain’t Gonna Need It” (YAGNI). And I get it. But do we really not care about expanding the software?

And this is the biggest internal conflict I struggle with between my coding style and my philosophical beliefs. Why build software if you don’t want it to be used by an expanding group of people? There’s no shame in hobbyist programming. But if you’re a professional programmer, you’re doing it to make money and/or to improve the lives of your customers.

So, can we be pragmatic? Can we try to be a buddha in a setting so sterile as a cubicle? Can we have one foot in commerce with another foot in calmness? The coding technique below will (in my opinion) help you to make way for the future while calmly focusing on the present.

Seeing the car crash of the future… and remaining calm

So consider the fact that when you get new users, you should hopefully be learning about the needs of your new customers. And new use cases means new features to write. And here’s the classic example. Today, we only deal with 3 lights. But what if we start selling the software in other states? For instance, the state that I live in has a blinking red light where you’re required to stop first before you go (kind of like a stop sign). Let’s see if the code that worked before has protected us from the future– can you spot the calamity that would occur?

Hold on a second, if the driver saw a red blinking light… wouldn’t that fall into the fall-through/else case? Wouldn’t they… oh no! Kaboom!!! Let’s see if we can prevent that future car crash but without having to do too much more work in the present.

Defending the future: the “never” type comes to the rescue!

Thankfully TypeScript has a language feature called the “never” type that allows the compiler to identify when every case in a union of types (or every case of an enum) has not been accounted for.  As you can see below, by not allowing the series of if-elses to fall through to a default else, the compiler will tell us that we forgot to instruct the driver how to respond to the “red blinking light.”

And now the driver won’t get into a car crash when we decide to start handling blinking red lights… because we literally couldn’t compile the code until we instructed the driver how to respond to this new case. In the original example, the code would have told the driver to just “go.” That doesn’t seem mindful to me.

The beauty of this defensive programming technique is that it costs almost no time to add exhaustive type checking to your code. The experienced programmer part of my brain knows that coding defensively is the simplest and best way to look out for the user’s needs. But, I worry sometimes that my career prevents me from truly acting like a Buddhist. Hopefully techniques like this “assert never” approach will allow me to strike a balance. After all, I’m just human. And Buddhism teaches us to love our humanity and to accept our emotions.

But what do you think? I’d love to hear your thoughts on Twitter and about your thoughts on the healthiness of defensive programming. Do you think it’s worrying too much about the future? Should you only concentrate on what the software needs to do today? Or do you think it’s okay to code defensively?

3 thoughts on “Is “Defensive Programming” actually healthy?”

  1. I run into this all the time. I tend to worry about the future as well. The way I’ve dealt with this is by using the philosophy that if it’s not static or it varies by location, use data not hardcoded logic. In this case it would be fairly simple to set up a table that has all of the variations of the signal colors by location and the corresponding action.

    Takes a bit more time to think about, but it eliminates problems like this one. Unfortunately this is the moment where I get told I’m over complicating things.

    1. I actually think that solution would be pretty cool! 🙂 Hey, if it takes the same amount of time (or close enough) and if it protects the user… then I’d say go for it! 🙂

      Btw, what did you think of the compile time checking that TypeScript provides?

      1. I think not only about protecting the user, but also the business. Much better to make a DB change than a whole new release, especially if the change is only for one customer.

        In this case depending how it’s used, you could load the values into an object as a collection when needed, or at program startup to minimise DB calls

Share your experiences with a comment