Software Craftsmanship & Practice

Debugging & Problem Solving

Treat debugging as a disciplined search for a root cause, not a guessing game: reproduce the failure reliably, bisect toward its source, and fix the actual cause rather than the symptom in front of you.
  • "select isn't broken" — assume the bug is in your code, not the platform, standard library, or compiler, until you have specific evidence otherwise
  • Reproduce reliably first — a bug you can't reliably trigger can't be verified fixed, only hoped-fixed
  • Binary search / bisection narrows down where a bug lives — halve the search space each time, including git bisect for "when did this regress"
  • Fix the root cause, not the symptom — patching where a bug is visible instead of where it originates tends to have it resurface elsewhere
  • "Rubber duck debugging" — explaining the problem out loud, step by step, to anything (a colleague, a rubber duck) frequently surfaces the wrong assumption before the explanation even finishes

"select() isn't broken" is a decades-old piece of Unix folklore that generalizes well: the standard library function, the compiler, the framework you're using has been run by millions of people before you and almost certainly works as documented. The bug — the overwhelming majority of the time — is in an assumption your own code made. Starting the search there first, rather than "it must be a platform bug," resolves nearly every debugging session faster.

Sources
  • The Pragmatic Programmer (20th Anniversary ed.)Ch. 5 — Bend, or Break (Debugging)