This morning, I got my car key out of my backpack.
No, wait, you’re not reacting strongly enough. This was remarkable! Let me explain.
A Troublesome Discovery
I run carpool every morning. Recently, I’ve started unlocking the car before I leave the house so everyone can get settled in and buckled. At the beginning of the week, I tried to do this, but when I reached into my backpack for my car key, it wasn’t there. We were running late, so I ran back into the house, grabbed a spare, and ran back out. When I got back home, I put the spare back and figured I’d find my key on my desk or on a flat surface somewhere.
I didn’t really look hard for it though, so every morning this week, I grabbed the spare key, ran carpool, and put the key back.
Thursday night, as I was thinking about it being the end of the week and still not having found the key anywhere, I finally did an in-depth search. I checked my desk again. Under things on my desk. In my cable and adapter bag. In my backup backpack (don’t ask). In my pockets. In the pockets of all the pants in the laundry. In the cubby where we put random things. No luck.
Deflated, I put the spare key on the counter so it’d be ready in the morning.
But this morning, I had a revelation: I hadn’t challenged my assumptions. So I checked my backpack, but thoroughly this time. And sure enough, the key was there, just in a different pocket than usual!
An Embarrassing Realization
I immediately realized the trap I had fallen in. I made an assumption (no key in backpack) and I held onto that assumption for days like it was the truest thing in the world. And that simple action, repeated over and over, led me down a trail of wasting time, feeling frustration and worry, and taking all these extra steps.
This entire escapade is even more embarrassing because I was part of writing Debugging Series 2021, and we talked about assumptions in multiple articles like Debugging: Listing Your Assumptions and Debugging: Navigating the Maze.
And while I don’t want to rehash the topic of assumptions in depth, I want to bring it up because assumptions are insidious. They creep up repeatedly despite your knowledge of them, and not falling victim to them is one of the most important things you can do as a developer.
Don’t start by believing anything, especially yourself, until you’ve proven it’s true.
A List of General Assumptions I’ve Made
- What the actual problem was, based on an error message or my own initial thoughts.
- What a function was returning.
- Where a function was returning.
- That other people’s code works as documented.
- That my code works as documented.
- Any aspect of time (I have 95% stopped doing this because of posts like that).
- That I replaced every instance of a name while refactoring.
- That it would work the first time (no, no, really).
- That it would work in production.
- And tons more.
A Way Forward
At the end of the day, the only assumption about time that I can make confidently is that I will spend more of it solving a problem if I assume I know what’s wrong.
So how do you stop trapping yourself in assumptions? Here’s a quick list:
- Start by calling yourself out. Identify that you have some assumptions and what they are.
- Write a permanent test of your assumptions. For example, you might add a test that
user@domain
fails the project’s email validation; if a similar pattern isn’t part of the repo already, that’s a valuable long-term addition. - Write short temporary tests for micro-assumptions (e.g., If you look up a value in
a newly-created empty hash, will it return an empty string?). These temporary tests
verify your understanding of how the language behaves. Does
false.blank?
resolve to what you think it should? You wouldn’t add such a test to the project, because it’s how the core language behaves, but it’s valuable to test it to make sure you understand what’s going on. - Cut and paste code, strings, URLs, values, etc. into a different
text editor. Run a search to see if things you think are the same are the same.
For example,
98e03859b97c60c1b7e2d547fiae4401
and98e03859b97c60c1b7e2d547fіae4401
are actually different. - If any logical steps involve decisions when something is blank / empty / null, verify which path you’re traveling with breakpoints or logging.
- Come to think of it, log messages have a surprising way of revealing assumptions (e.g., “That’s not a space”, “Why is an Ɇ in there?”, “Why am I seeing only one value?”).
- Go through troublesome code line-by-line and verify that what you think is happening is happening.
I could keep thinking of examples, but I want to reinforce the idea of remembering to challenge your assumptions rather than come up with an exhaustive list.
I’ll leave with the thought that the biggest assumption you can make is that you are immune to making assumptions because of (reasons). Instead of doing that, do this:
Stop, assess, prove, and continue!
P.S. If you’re wondering about that string inequality example and you think they are the
same, look at the underlying Unicode character for i
vs і
.