Imagine you’re designing a high performance system. What hardware would you use? Would you use only general purpose CPUs? Probably not, you’d also use GPUs. As high performing engineers, we also need to move beyond our general purpose hardware and leverage specialty hardware. But our general purpose hardware is not an Intel Xeon W-3275M CPU, it’s the part of our brain that handles abstract reasoning. Our specialized hardware is not an AMD Radeon RX 5700 graphics card. It's our eyeballs and visual cortex.
To understand how to debug with our eyeballs, we'll walk through a real world example of using eyeballs to debug, and afterwards learn from it.
This actually happened
A friend of mine is going through the greatest programming book of all time. And like any good engineer, he wrote a bug. He knew there was something wrong in a “cond” statement, but he didn’t know what. (Although the following code is written in Scheme, the less you understand about the following code, the more you’ll appreciate how powerful the technique of debugging with your eyeballs can be.) Here's a stripped down version of his code:
(cond p1
e1
p2
e2
p3
e3)
He thought hard. Reasoning about what might be wrong. Looking at the definition. Looking back at his code. Back at the definition. Back at his code.
No progress.
He tried comparing it to a correct use of cond:
(cond (p1 e1)
(else e2)))
Looking at the correct example. Looking at his code. Looking back at the correct example. Back at his code.
No progress.
Then, he tried visually reframing the code by indenting each nested function call.
His code:
(
cond
p1
e1
p2
e2
p3
e3
)
Working code:
(
cond
(
p1
e1
)
(
else
e2
)
)
Aha! He saw the statements were shaped differently. The difference became immediately obvious. The second cond groups has parentheses that the first cond does not. The parentheses go around each “p-e pair”. Therefore in the first cond, he should group each “p-e pair” in parentheses. Bug debugged.
Analysis
Now that we've seen a particular example of debugging with our eyes, we can learn from it. At first, we had no idea what was wrong with our cond statement. We didn’t know where the problem was. It could be anything. Maybe the order was wrong. Maybe one of the p(redicates) was malformed. Who knows? Then, we reframed the situation. We turned subtle parentheses into flamboyant indentations. Our broken version was juxtaposed against a pristine working example. Instantly, our eyes found the working example’s extra parentheses. They screamed out “look at me, I’m different”. Once there, our brain took over the last few steps to finish up.
Here we see the secret to debugging with our eyeballs: visually reframing the situation (we say situation rather than code because sometimes we need to reframe data as well). Once the situation is represented visual, our eyes and visual cortex are well tuned to notice oddities and irregularities. If we go a step further and compare two similar but distinct visuals, our eyes will spot the difference instantly.
4 tricks to debug with your eyeballs
Rule of Silence
“When a program has nothing interesting or surprising to say, it should shut up”
It's easy to notice something odd if it's the only thing on the page. If it's hidden amongst 100 lines of useless information, we might miss it. The best way to capitalize on this is to change our programs to print nothing upon success. The second best way is to get rid of noisy success messages with a tool like grep.
cat noisy-logs.log | grep -v "STATUS: SUCCESS"
Spot the Difference
Our eyes are very good at noticing differences. So, if we can turn a debugging problem into a “spot the difference” problem like we did above, our eyeballs will speed up our debugging significantly.
Shape it
The previous two examples work well for differences you’re expecting (an error, a known good example compared to a known bad example). How can we use our eyeballs to help us spot differences we’re not expecting? Shape.
Which difference is easier to spot?
1
1
1
1
1
7
1
1
1
or
X
X
X
X
X
XXXXXXX
X
X
X
Both represent the same data, a 7 hidden amongst 1s. But we can easily see XXXXXXX among Xs, even from a distance. If we can convert our “notice information you weren’t expecting” into a “notice a shape you weren’t expecting”, we are much more likely to find it.
What’s black and white and red all under?
A misspelled word! The spellcheck UX is a fabulous example of using color to help us debug with our eyeballs. Finding misspellings in an sea of text is tough. We can’t see them. They look like normal words, but only when we think carefully (or look them up in a dictionary) do we notice an issue. But with spellcheck, when we misspell a word (which is like a bug), then below the word is a big red line! Surrouned by white and black! It screams to our eyes, "I'm broken, fix me!" And once our eyes alert us to the issue, we’re able to fix it.
Conclusion
Our eyeballs help us debug much more quickly. Once reframed, they spotted the error with our "cond" statement in a second. We have a bag of tricks to empower our eyes to find our bugs. Next time we're debugging, we'll be ready. We'll not only think what's going on? what’s broken? But also, how can I visually reframe the bug? How can I make the bug easy to see?
If you don’t want to miss out on more ways to code faster, just click Subscribe now below