Fuel, Air, Spark
I have a lawnmower. When it doesn't start, I have a few tricks to try, such as checking to see if there's fuel in the tank. When it still won't start, I require assistance.
A heroic family member has helped me a few times, and he gets the engine running, every time, in minutes. Why? Because he has an effective mental model of how combustion engines work.
Engines are fundamentally pretty simple. There are just a few things that make them start: fuel, air, and a spark. When troubleshooting the engine, you want to start with these systems.
- Fuel: is gasoline getting to the engine?
- Air: is oxygen available to the engine?
- Spark: is the spark plug sparking?
Most of the time, if the engine won't start, one or more of these systems is not working.
Imagine we have a spark and air. But we can see that there's no fuel getting to the engine. From there, we can work on that system: the tank, the line, and the filter. We check each of these.
Let's transfer this idea to web development. Imagine we're seeing something surprising in our browser: instead of my user avatar, I'm seeing the avatar of a different user. Not good!
Our systems would be the front-end application, the API, and the database. How could we quickly assess each? Since we found the bug in the browser, I'd start with the front-end application.
On the front-end, what is the browser receiving from the network request, and what is it doing with that information? Let's imagine that it's receiving a URL string and showing it in an img
tag. At this point, we get to say: "This is not a front-end issue." We don't need to look at any JavaScript components or read an MDN page about strings.
On to the API: what value is being passed to the front-end? We look in the network tab and see that the user
payload contains the wrong URL! So this is an API or data issue.
Lastly, we look in the database and see that users have a single, unambiguous, authoritative representation within our system, which includes their uniquely constrained avatar URL string. And for this particular user, the URL is correct, and different from the one we're seeing in the browser.
Not a front-end issue, not a database issue... it must be an API issue! The API is doing something incorrectly with the user it's asked to return.
In a matter of minutes, we've reduced the potential surface area of this bug's origins from the entire internet to a single line of controller code in our codebase.
Systems thinking neutralizes two distracting debugging patterns: prematurely jumping to subsystems, and backtracking.
Jumping to subsystems shows up in a variety of ways, such as digging into a random library or chasing long-shot explanations. Perhaps we found a bug in React? Maybe the user needs to upgrade their browser? These are improbable explanations, and we shouldn't be starting with them.
Backtracking, or revisiting systems we've correctly dismissed, is distracting. While looking at the database, we think: "Maybe this is a bug in the front-end?" It's tempting to leave the thorny SQL code we're looking at. But, if we've dismissed the front-end as a cause of the bug, going back there without a good reason isn't very mindful. It's like replacing a working spark plug.
Note: I'd like to give credit to this metaphor, as I think that I heard it on the Developer Tea podcast from Jonathan Cutrell. I've failed to find the exact episode I may have listened to a decade ago. It's been a crucial metaphor to me and I'm proud to be restating it here.