Debugging is perhaps the skill that I find programmers have the hardest time exercising. It is also the most difficult to teach. Debugging, to me, is both a scientific discipline and an art. It often requires you to reach beyond analytical thinking to rely upon your own intuition in order to solve a problem.
Many developers use empirical approaches, systematically addressing each possible problem branch. If A, then B. If B, then C. If C, then D. This analytical approach works well and is easy to teach. The problem I find, though, is that many focus on identifying solutions before fully grokking the problem. This leads to approaches that begin with D and work their way backwards to A, resulting in wild goose chases and wasted time.
That’s not usually how I approach debugging. For me, an approach based on intuition is key. But intuition is a tricky thing, isn’t it? After all, having a gut feeling about something seems mystical and a little paranormal. I don’t think it is, though. Wiktionary defines intuition as “immediate cognition without the use of conscious rational processes.” Here’s how I think it works. Your brain is constantly making computations, much like a Frank Herbert mentat. It has the data it needs, makes the calculation faster than you can blink your eyes, draws conclusions, and gives you the response in the form of a short-but-sweet gut instinct. That’s immediate cognition, and you weren’t conscious of any rational process being used.
This constant computation is something everyone does, but in Western civilization, we have suppressed it in favor of the rational approach. We can learn to develop it, listen to it, and, along with analytical thinking, make it a part of our standard thought processes. Here are some ways to make intuition a part of your debugging habits.
As developers, when we encounter problems that require intense debugging, we’re often in a rush, especially if it’s something that affects a production environment. This rushed mindset creates the worst possible conditions for allowing you to effectively target the problem and identify a solution. When rushed, you don’t think clearly about where to begin, much less how to solve the problem. To think clearly, you must slow down.
When you find yourself rushing to fix a bug, it’s best to stop what you’re doing, close your eyes, take a deep breath, and let it out slowly. I know it sounds hokey, but this isn’t transcendental meditation. It’s perspective. It’s focus. When you take the time to slow down and focus, you can tap into your intuition, using it to discover where to begin and how to solve the problem.
In his biography of Steve Jobs, Walter Isaacson quotes Jobs as saying this about intuition and slowing down your mind:
“If you just sit and observe, you will see how restless your mind is. If you try to calm it, it only makes it worse, but over time it does calm, and when it does, there’s room to hear more subtle things — that’s when your intution starts to blossom and you start to see things more clearly and be in the present more. Your mind just slows down, and you see a tremendous expanse in the moment. You see so much more than you could see before. It’s a discipline; you have to practice it.”
Stop saying “I don’t know”
As developers, we like to focus on constraints. Software construction is all about finding the constraints of a problem domain and programming a solution to fit within those constraints. It’s no wonder our lives and jobs revolve around constraints, and we like it that way. But constraints can hold us back and squelch our intuition. When we assume we don’t know the answer to a problem, we impose a constraint upon ourselves that makes it more difficult for us to find the answer.
In her book, Grow Your Intuition: 6 Simple Steps, Suzan Bond says that we shut off our intuition when we answer questions with, “I don’t know.” She goes on to say, “When you stop using this phrase as much, you will open up your intuition. You’ll be able to see more possibilities, rather than limitations.”
It’s not wrong to admit lack of knowledge in an area, and I’m not advocating that you make up answers, but the truth is that you may already know the solution. Your brain already has the data it needs. Slow down. Take a breath. Ponder on it. Let your intuition speak to you. If you have trouble finding a solution, ask yourself what may be blocking you from seeing it. Don’t accept that you don’t know the answer. Accept that you must discover the answer.
The problem is in your code
Here’s a humbling but crucial notion. It’s never fun to accept the blame for something, so it’s easiest to point fingers at someone or something else. This third-party library or framework is terrible! John wrote this spaghetti code three years ago, and it’s awful! This programming language is a nightmare! Let’s face it, developers are proud folks and masters of hyperbole. I have learned, though, that the problem is most often found right in your own code, so it’s best to begin with that assumption.
Very early in my career, I worked with a developer — we’ll call him John — who always blamed someone else’s code when he found a bug. He loved doing this so much that he would leap from his desk, giggling, and run into my office to boast about finding a bug in some third-party library or even in the programming language we were using. John loved being able to say that the language was faulty and that he was responsible for finding it out. On more than one occasion, he had the programming language’s bug report form open and filled out before I was able to catch him and force him to readdress the issue by carefully looking at his own code. Every time, his code was at fault.
When you start with the assumption that it’s someone else’s code that has the problem, then you’re hurting yourself in several ways. First of all, you’re impeding your own ability to find the real problem because you start by looking in the wrong place. This costs you time. Secondly, you’re setting yourself up to look like an buffoon when it turns out your code was the problem all along, and you wasted time, energy, and resources trying to blame something else. Lastly, you hurt your reputation as a problem solver by passing the buck.
When you start with the assumption that the problem is in your code, then you display humility and leadership by accepting the responsibility to solve the problem. If it turns out the problem was, in fact, in someone else’s code, then you have instilled in others a great deal of trust in your ability to actively pursue solutions to problems.
Focus on the problem, not a solution
When you focus on identifying a solution before fully grokking the problem, then you’ve put the cart before the horse. Start at the beginning; start with the problem. I think this is difficult for many developers, because we like to jump to conclusions. I see both A and B, so it must be C, therefore D! Finding and implementing solutions is thrilling and satisfying for us. Finding problems? Not so much.
Keep in mind that the symptoms may not indicate the real problem. We know what they are, so we fix the problem by testing for and addressing the symptoms. Once the symptoms no longer appear, the problem is solved, right? Nope, now you’ve buried the problem deeper, and it’ll be harder to find next time.
A specific story from my career comes to mind where multiple, identical records were added to a database table for a specific action that should have added only one record each time. This resulted in the customer generating reports that contained multiple, identical records. That was the symptom. In an effort to appease the customer, a solution was devised to combine the records at the point in which the report was generated. This made the customer happy, but it didn’t solve the problem. In fact, now that the problem was buried, it was more difficult to see, and the database continued to fill up with bogus records.
Always get to the heart of the problem. Don’t just look at the surface symptoms and assume they are what needs resolving. Focusing on the solution won’t get you there. You need to focus on the problem. I find once I understand the problem — once I fully grok it — my intuition kicks in with a handy solution.
In his book, The Universe in a Single Atom, the Dalai Lama writes:
“The difference between science as it stands now and the Buddhist investigative tradition lies in the dominance of the third-person, objective method in science and the refinement and utilization of first-person, introspective methods in Buddhist contemplation. In my view, the combination of the first-person method with the third-person method offers the promise of a real advance in the scientific study of consciousness.”
While the Dalai Lama refers to the study of consciousness in this statement, the central argument of his book is that the empirical scientific method can benefit from first-hand experiential intuition and must benefit from it, if we are to make ethical advances in the sciences and understanding of our universe. I agree, and I believe that intuition can benefit even computer science and software engineering.
I can’t pretend to understand all the mysteries of the mind, nor can I purport to teach you all about intuition. I’m learning these things myself. However, I do know that intuition is something everyone can take advantage of. I rely on it daily. I’ve noticed how it has saved the day in countless debugging sessions throughout my career, and while I’ve known of the role it plays all along, I feel it is time to accept it and share my experiences using it.
So, be a better problem solver and debugger by tapping into your intuition. Learn how to slow yourself down. Be confident that you already know the answer. Show humility by first assuming the problem lies within your own code. Focus on identifying the problem; once identified, the solution will come to you. Combine the use of intuition with standard analytical processes.
You will be a better developer.