We've all been there. Coding away, solving a problem when all of a sudden we hit a blocking point. The thing we're trying to do doesn't work, or the problem seems completely out of reach. Heck, sometimes we might not even know how to begin solving the problem!
This might sound familiar, recent, even! After 10 years of working as a software builder, I still find myself getting stuck. I'll run into a bug that I can't reproduce reliably, I'll come up against an API that I can't seem to communicate with, trying to update a dependency will break others, or my CI builds just keep failing.
Let's take a look at a few tips to help you get unstuck!
Take a break, step away from the code!
This tip has helped me many times in the past, so much so that I gave a talk on this very topic!
When I get stuck in a particularly sticky problem, I tend to get bogged down by it and try and hammer away at it, attempting to push through the frustration and/or exhaustion. It ends up in time not well used, or worse, my solutions might miss the mark.
So as the title implies, it helps to just, leave it for the time being! Depending on the time and looming deadline, this can vary in efficacy, but I find that if I go for a walk, or stop for the day, I can let my mind either work on the problem in the background or even coming back can bring in a fresher perspective that really jumpstarts a better solution!
Reframing the problem
Oftentimes when stuck on something, it might help to consider looking at the problem differently! Having a different perspective might even make us ask the question of whether the problem we're trying to solve is the right one. As written by Thomas Wedell-Wedellsborg:
Most people are fairly good at solving problems – but they are bad at diagnosing the right problems to solve.
Breaking the problem down into smaller problems
This approach to problem-solving is similar to that applied by Divide and Conquer Algorithms, where, as the name implies, we reframe the problem as a set of smaller problems, whose solutions are smaller by extension. What we can then do is approach each of these in isolation. This frees up our mind space to laser focus on those smaller problems and lets the larger solution build up!
One example of a tool to divide and conquer is git-bisect. Yep, built into your git tools!
git bisect is a command built into git with the purpose of helping us find out at which point we introduced a change to our codebase that we didn't want to add. By splitting all of the git history and checking whether the problem persists in each split, we drill down quickly to find out the commit that introduced it! This is also known as a Binary Search:
Looking things up effectively
No matter the skill level, it's super-valuable to look things up! Be it via online search engines or documentation.
There are brilliant technical guides out there for how to look stuff up on Google or DuckDuckGo, such as using quotation marks for terms that have to be included, or gradually making search phrases longer. Beyond that, some tips I've picked up over the years:
- Look up that error message as-is: Loads of folks have likely run into the same problems. Even if they don't match 1:1, you'll likely unlock something!
- Plug in that Stack Overflow solution: I recently learned that Stack Overflow's license allows reuse under Creative Commons Attribution-ShareALike, meaning you can reuse the code providing you add attribution. That said, in order to improve your understanding of a solution, it's encouraged to try and refactor that code, putting it into the best way that works with the style of your codebase. You'll often find that's required anyway!
- Look up that aspect of a library in their Github repository: When something hasn't quite clicked in a library I'm using, it helps me to go into their repo online and see either what issues have been brought up on the topic, or even start trying to diagnose the issue in the library and potentially make a contribution!
The screenshot above shows lots of issues when I look up "compileDebugJavaWithJavac". I need to clean up my notifications, I know!
Although we have tools to help us debug, this doesn't make all those tools debuggers.
One of my most-used tools is a print statement. It goes by many names in different programming languages, be it console.log, or puts, or printf, or System.out.println(). I've even gone and used alert in React Native projects!
And this is totally fine. If it helps you drill down to what's causing the problem, why not?
Various platforms will have debuggers on them too, like the web! Most browsers will have their own debuggers built-in, such as Firefox's Developer Tools or those from Google Chrome, both of which are extensively documented. But this isn't just limited to the web, we've also got specific debugging tools, like LLDB for all your macOS/iOS debugging needs, pry for Ruby, and so on!
Indeed, even editors like VSCode have their own debugging tools built-in for several languages!
The most important part of debugging for me is to leave no stone unturned and try every theory I might have. You never know which piece of the puzzle is faulty!
Reaching out for help
Sometimes, with our heads buried in a problem, our perspective can get clouded. Having someone else step in with either more experience in the area or with their fresh perspective can be so handy in unlocking the answer!
How long should I wait before asking for help?
This is one of the trickiest parts. Spending too little time on trying to solve a problem blocks us from practicing and/or learning problem solving, but taking too long or never asking for help can hold a timeline or team back (I'm definitely in the latter camp myself, (maybe even to this day a little (working on it!)).
One piece of advice I was given early was to be consistent in how long I wait. Of course, this can vary by team, project, and other factors, but my rule of thumb is to give something half an hour before reaching out.
How to ask for help
Asking for help involves bringing an outside person into the context you're in. Doing so effectively is critical to maximize the help you're about to get.
This involves things like:
- Asking pointed, narrow questions: If you come to someone and open with "this doesn't work, could you please take a look?" is very different from saying "I'm having some trouble logging in since updating to the latest devise gem, could you please take a look?"
- Sharing what I've tried: To save time, it helps if I share with the person who's helping me what I've already tried, to not spend time on those.
- Reproducing the problem: It's also good to have a set of steps handy so that if this is an asynchronous or remote request for help, that the other person can try it out and confirm that there's indeed an issue.
If possible, when reaching out for help, it's so helpful to practice pair programming. Most likely, if receiving help, you'll be driving, meaning you'll be doing the coding, but you could also be navigating, meaning you'd be giving tips as your helper as they drive.
Having established the problem, communication is critical to ensure a successful pairing session. More on pair programming coming soon!
Let's be clear, it's ok to get stuck
In an instance of "do as I say, not as I do": I often panic when stuck. Impostor syndrome sets in, and I start wondering if I've ever been a competent engineer.
As engineers, trying to solve new problems or trying to integrate solutions into existing ones is a tricky matter!
One thing that I try to keep in mind when working on a problem is that it will eventually be resolved, and that patience is key. We will eventually reach that "Aha!' moment where everything will click.
What about you? How often do you get stuck? How long do you wait until reaching out for help? We'd love to hear from you! Hit us up on Twitter or email us devrel[at]codesee.io.