Oblique Strategies are a series of pithy prompts to help with lateral thinking (e.g., “Try faking it!”). The list in this blog is similar to those strategies (with some overlaps), but it’s tuned for getting unstuck while developing software. You probably have your own list of things you do when you don’t know what to do — maybe you already do some of the things in this list, or perhaps you have some strategies that are missing from this list.
You may find it helpful to bookmark this page and return to it the next time you’re inclined to guess at what to do next.
Before we begin with the altenatives to guessing, let’s answer the question “Why not just guess?”
Background: why not guess?
What do I mean by guessing?
Suppose I have a bug that could be somewhere in any one of five files. I pick a file at random and attempt a fix. It doesn’t work. That could be because my fix was bad, or because it was the wrong file. I choose a different file, and attempt a fix. That doesn’t work, either. Again, it could be my fix or the file that’s wrong. This continues in an ever-expanding tree of uncertainty.
In this post, “guessing” refers to a troubleshooting technique based on luck.
I guess because I don’t know what I’m doing
When I have to guess, it’s because I am missing some knowledge or skill.
Sometimes, it’s general knowledge (e.g., “How does npm publish
choose which
files to upload?”), and other times it’s specific (e.g., “What’s wrong with
my project configuration?”). I guess because I want to get this working
(quickly) more than I want to learn why it didn’t work.
Guessing is easy
If I don’t know where to make the change to solve the problem, the option that takes the least effort is to roll a die (often figuratively). Pick one arbitrarily: the first file I see in my file explorer, the file that is already open, the file we edited most recently, etc.
Guessing is slow
Unless I get lucky, I’ll have to make many attempts before I hit on the right one. What’s worse, every time my prospective fix doesn’t work, I don’t know if it’s because I put it in the wrong spot or because the fix is wrong. Am I one stray punctuation mark away from everything working, or am I in the completely wrong file? The uncertainty cascades, making the solution harder to find.
Guessing hurts my career
I guess because there is something relevant to my work that I don’t know. When I guess, I avoid learning. That means the next time I hit this problem, I still don’t know. Guessing can be a shortcut to completing this week’s work, but it does not equip me to be more effective next week, month, year, etc.
By contrast, learning compounds: the more I learn, the less I guess, and the faster I work. When I learn today, I make myself more productive in the future.
Guessing is stressful
When I’m in a long chain of guesses, I am out of control. My success or failure depends on luck. Will I solve this before lunch? Will I solve this today? I can’t say. Instead of a sense of steady progress, I’m filled with uncertainty and unease. That’s not a recipe for a fun, satisfying, and effective work day.
One guess is good, many guesses are slow
If my first guess is right, that was a very inexpensive solution. In a single attempt, I solved the mystery without having to do any extra learning. Awesome!
The more guesses I make, though, the higher the cost and higher the confusion.
So – in general – I’m likely to make one or two guesses, but after that I reach for a different strategy, something that does not rely on luck.
Alternatives to guessing
When I have no idea how to solve a problem, I reach for a technique like one of the following. As I progress in my career, I collect more strategies to use instead of guessing. I sometimes learn them from someone else (a teammate or an author whose work I’m reading), through experimentation, or variations on a theme. You probably have your own list. This list may give you some ideas of strategies to add to your list. At the very least, I hope this list inspires you to intentionally reach for an alternative to guessing — so you can enjoy the expedience now and be better prepared for the next mystery you face. If this is a totally new idea to you, consider bookmarking this page and referring back to this list when you’re tempted to guess more than once. As time goes on, you’ll internalize the techniques that work well for you, and you won’t need to come back here.
Instead of guessing, you can choose one of the following (whatever makes sense for the problem at hand).
Fix my mental model
- Draw a picture
- Write a failing unit test that describes the expected behavior
- Write a description of the problem
- Explain how the observed behavior is impossible (e.g., “we’re seeing X, but it should be impossible to get X because of A, B, C”)
- Clean up (refactor) the code: rename variables, extract methods, inline methods, and generally restructure stuff (using provably safe refactorings, ideally supported by your IDE). The easier the code is to read, the more brain space you have available for solving the problem. (Conversely, the more convoluted the code, the higher percentage of your thinking power is dedicated to just understanding what you’re reading. That can leave very little space for actual problem solving.)
- Make a detailed description of the problem** in your task-tracking software (ticketing system, Kanban board, etc.). Optionally, include steps to follow to solve it (even if you don’t know how to complete those steps).
- Read the code to get a better sense of what parts there are and how they fit together
- Read the code to understand how the functions link together. Draw a picture or take notes of which functions are called in which files. Start with the main method that’s called, and work from there. Or, start with the last method that’s called, or the location of the stack trace, and work upwards from there.
- Read the entire error message (so that you know exactly what issue is you need to solve — “If you aim at nothing, you will hit it every time”).
Clear the noise
- Fix all the warnings (compiler warnings, unrelated tests that are failing, IDE warnings, etc.)
- Write “bad code” Meaning, ignore all warnings, code style problems, failing tests, etc.; hardcode everything; use admin credentials; hack it until it works.
- Write your solution in plain English. Once it’s all written down, convert it into code.
- Write down a list of things that you know don’t work. (And, perhaps, update this list as you try more things.)
- Find someone who doesn’t know how to program or who knows nothing about your domain or tech stack, and explain the problem to them. This forces you to skip over the finer details and get to the main point. Their questions will help you clarify your understanding. If you can’t find anyone to talk to, write an email (even if you never send it) that describes the problem. It’s helpful to have a specific person in mind that you’re writing to, because even if they’re not there to ask you questions, you will naturally imagine how they’ll respond to your email and fill in gaps or omit details as needed.
- Create an MCVE (Minimal, Complete, Verifiable Example).
Generate novel ideas
- Walk away. Lock your computer and do something where your mind can wander. Allow yourself to think about the problem if it comes to mind, but make no effort to think about it — let your mind wander. Some ideas: go for a walk, make a sandwich, take a shower or bath, do some laundry, etc.
- Make a list of things you could try. Make the list as long as possible before you start on one of them.
-
Write an absurdly high-level plan, and then follow it. For example, if
npm publish
isn’t working, you might make a plan: “skim read the npm publish docs, watch a video tutorial on usingnpm publish
, and then think of the next step to try”. Or for a different problem you might say “Write down three crazy ideas. Try the first one. Try the second one. Try the third one. Revisit this plan.”
Gain general knowledge
- Find a related tutorial (blog or video) and watch it
- Find the official documentation for the tool, API, method, platform, or other technology that you are using. Skim read the documentation to get a better general idea of how it works, what you can do with it, etc.
- Find an expert and ask them to mob/pair with you
- Find an example of something similar
- Write a list of what you do know related to this problem. Are there any gaps? Go learn (read/watch/listen) to fill the gaps.
- Write a list of what you don’t know related to this problem. Go learn (read/watch) to fill those gaps.
- Take a multi-day study break. Stop working on the problem for a few days. Buy a textbook or an e-learning course related to what you’re working on. Study until you feel like an expert in this one thing. Learn the ins and outs. Write a blog summarizing your findings. Teach a coworker or friend. Try building a little project from scratch using the technology. Finally, after days of this, once you feel really comfortable with the technology, revisit the problem.
Gain specific knowledge
- Write down a question about something you don’t know about your system; think of an experiment you can do to answer that question.
- Bisect the problem space. Using a binary search, narrow down the location of the problem. For example, if you have a client/server architecture: use logs to determine if the problem is in the client or the server (“Is the request to the server correct? Is the response correct?”). Then, use logs to find the file where things stop working: pick a file roughly halfway through the call stack, and determine if the behavior is good there. If it isn’t, look before the file. If it is, look after. Repeat until you know the exact place where things get awry.
-
Do a web search for the error message (including any relevant technology names like the programming language or important frameworks). Consider including quotes around the error message. For example, if your Angular Karma (unit) test throws the error
Template parse errors: ‘app-nav’ is not a known element
you can search for
“Template parse errors” “is not a known element” Angular Karma
This search contains 2 multi-word strings that are likely to match the specific error, but it removes the names that are specific (custom) to your project.
- if you don’t know what libraries your project uses that relate to the problem you’re facing, start by figuring that out so you can refine all your subsequent web searches
- Use a debugger
- Read the git history of related files. What has changed recently? What files changed together? What tests were changed? What did the change authors write as a commit message? Are there links in the commit messages to a task in your task-tracking tool or pages in your wiki?
- If the thing worked before but doesn’t work now, use git bisect or a manual binary search through your git history to find the change that introduced the problem. Use that information to understand why the problem is happening, and then think of a way to fix it. (Maybe you reverse the problematic change. If necessary, you can re-implement it correctly. Maybe you discover there are two conflicting goals for how the system needs to behave and you need to chat with your product owner to decide which behavior we want. In any case, seeing the change that introduced the problem should give you some idea of what to do next.)
- Stop working on the problem. Fix a bug or make some other small improvement to the system. When that’s done, come back to the problem.
TL;DR
When you’re tempted to guess, learn something instead. If you must guess, make sure you’re learning something from the results of the guess so you won’t have to guess next time. Your success does not have to rely on luck, and the strategies above can help turn a guessing situation into a learning situation.