Why I Hate Surprises

Hey, I’ll admit it: surprises can be fun! Christmases, birthdays, even gender reveals. You can expect and look forward to a surprise at each of these.

When you’re programming? Not so much. When it comes to code, more often than not, surprises tend to be unpleasant.

Startled Cat
Surprisingly, wide eyes and hissing are a big part of the coding process as well.

Managers: this post starts off a bit technical, so if you’d rather jump to the practical points, skip down to the next heading for some more general advice.

Here’s a personal example: a few days ago I was sitting back in my comfy office chair, reading through some Python code I’d received from a friend. Everything was going well, until I saw this:

setattr(obj, "some_attribute", value)

To explain, the setattr function is used to set an attribute on an object, and takes a string as the second argument - the name of the value to set.

This is useful if you need to set an attribute’s value based on a dynamic attribute name. Something like this would work:

for suffix in list_of_suffixes:
    setattr(obj, "attr_" + suffix, value)

Now if you’re not doing anything dynamic, then why would you use setattr? As opposed to something more idiomatic, like:

obj.some_attribute = value

That’s the question I found myself asking after seeing the code in the first example. In my experience there should be no difference between the two methods. But then I reminded myself: I don’t know the ins and outs of every single Python class. Perhaps the developer had a reason for doing it that way. Or perhaps they didn’t know what they’d done wrong. Regardless, they hadn’t left any comments or explanations for why they’d included such a nonstandard implementation, so I was left guessing.

Whatever the reason, I then felt compelled to take some time to follow up with them and see what was up, hoping that they’d either “fix” it or add a comment explaining the weirdness. (For what it’s worth, in this case there was no particular reason for using setattr. The code was changed back to the “normal” way.)

End of technical stuff – managers read on!

The point is that because of an unexpected surprise in the code I was reading, I was struck with uncertainty and had to spend some time poking around to find out why the code was written the way it was – time that I could have spent on other problems, or on reading more pieces of code. It broke my workflow, and occupied my headspace. Hardly an earth-shattering problem, but that’s the thing about small surprises – run into enough of them, and over time, they can really add up.

A car analogy

Like many software problems, this can be reduced to a car analogy.

Let’s say that every day you go to get in your car. You pull out your keys, put them in the lock, then turn it. The door unlocks, and you get in and happily drive away.

One day your friend who drives the same type of car hitches a ride with you. She watches you get in and then says, “Hey, you know you can just unlock it with a remote, right? That way, you don’t have to fiddle around with the keyhole.”

RC Car
In my defense, remote controllers usually look cooler than that.

Maybe you really didn’t know and can then start using the remote; alternatively, you can explain to your friend (with a comment) that the batteries are flat, so this is the only way to do it with your car.

What causes surprises?

The causes of a lot of surprises is that you don’t know what you don’t know.

You might do things that seem to work OK, but without in-depth investigation or help from someone else with more specific knowledge, you may very well never know if there’s a better way. Even experienced developers run into issues like this.

Another cause can be incomplete refactoring. Perhaps you’re working on some code that used to do things a certain way, but you’ve found a better (more idiomatic?) way. At some point, maybe you got distracted or just plain forgot, causing you to refactor the start of the code, but not the end… leaving readers to wonder why, without being able to look into your brain and see your full reasoning.

The upsides of surprises, and avoiding them anyway

Now, there are upsides to these sorts of nuggets of code; while they do shake you out of your headspace, they might also prompt you to go looking at code changes that you’d never looked at before. Maybe you’ve just seen one of those better ways, and the subsequent documentation trawl has left you with a whole new set of tricks and techniques to incorporate into your code. Or maybe spotting someone else’s mistake has helped you to discover possible reasons why your own code isn’t working. On that basis, can’t surprises be helpful?

Well, yes and no. The issue isn’t whether or not you learn, it’s the uncertainty involved in the process. Did the other dev use a package or method that you’ve never heard of, or was this just a typo? Are there good and solid reasons for them to have made that choice, or did they not know what they didn’t know? Having to try and get into the other dev’s head is a process that can take hours, hours that don’t need to be spent that way.

Flower Surprise
It might be nice if they were the intentional sort of surprise… but usually, they’re not.

The fact is that while you can learn something from these surprises, you can learn faster if they aren’t as surprising. The right comment in the right place can explain whether a string of code is the result of refactoring or updates or a new technique that you’ve just read about and tried experimenting with. If someone knows that, they can figure out whether it’s something to look into themselves, or something that can be passed over.

Is it possible to create a surprise-free environment?

Mmmmmmmaybe? The fact is that while you can preach best practices to all and sundry until your tongue falls out, there’s no good way to force everyone to apply those practices. That being said, you can reduce the number of surprises that you leave other people, and suggest that other developers do the same. Here are some of the better tricks for doing so:

  • Be cognisant of anything “magic” or “hacky” that you’re working with. Think if there might be a less-magical way of achieving the same result.

  • Comment your code. If you’re forced to do something weird, make sure to comment it to explain yourself. Even if it’s only to explain it to yourself! I can’t count the number of times I’ve gone over my old code and asked, “What was I thinking?” Make it easier to understand for both you and everyone else.

  • Track your workflow. If you’re refactoring your code to reflect some new changes, updates or newly-discovered techniques, go through beforehand and leave comments in your code at the points where you need to perform refactoring. It’ll make it easier to avoid missing a spot, and if you still do miss something, the next dev to look it over will at least know why the code is strange there.

  • Perform code reviews. Get your peers to review what you’re doing and let you know if anything is surprising. That’s how I found the example code that prompted this post. If something’s clear to you but not one of your peers, they should let you know to fix or comment it.

Comments
Take the time to put down your thoughts.

Aside: setattr stupid tricks

When researching this article, I wondered about use cases for setattr without dynamic attribute names; for example, stupid characters that wouldn’t normally be allowed. For example, this implementation is illegal:

obj.attribute-with-dashes = value

Whereas this is legal:

setattr(obj, "attribute-with-dashes", value)

Of course, doing so means that you’ll then need to access the attr with getattr:

value = obj.attribute-with-dashes  # not valid
value = getattr(obj, "attribute-with-dashes")  # you have to do this

You can also set attributes with spaces – even empty strings are valid!

setattr(obj, " ", value)  # works
setattr(obj, "", value)  # works too!

Note: don’t do this. Sure, it works, but it’s just bad code. Even with a comment, most devs (including me) will decline your pull request if they see this.

Conclusion

Like death and taxes, surprises are inevitable. But if you’re careful about your code and think about how it’s going to be read, you can cut down your surprise count and make life easier for yourself and those around you. This approach, combined with peer reviews of code, can bring about a smoother environment for you and your team.

About Tera Shift

Tera Shift Ltd is a software and data consultancy. We help companies with solutions for development, data services, analytics, project management, and more. Our services include:

  • Working with companies to build best-practice teams
  • System design and implementation
  • Data management, sourcing, ETL and storage
  • Bespoke development
  • Process automation

We can also advise on how custom solutions can help your business grow, by using your data in ways you hadn’t thought possible.

About the author

Ben Shaw (B. Eng) is the Director of Tera Shift Ltd. He has over 15 years’ experience in Software Engineering, across a range of industries. He has consulted for companies ranging in size from startups to major enterprises, including some of New Zealand’s largest household names.

Email ben@terashift.co.nz