BlogsAndLinks.com
Programming

How to Actually Debug Code Instead of Guessing

Mark · Sep 2, 2026 · 5 min read · Updated Sep 2, 2026
Xin
How to Actually Debug Code Instead of Guessing

New programmers often debug by changing a line, running the code, changing another line, running it again, and hoping something clicks. Sometimes it works. Mostly it wastes an hour and leaves the code messier than before.

Debugging is a process you can follow on purpose. It isn't about being clever. It's about narrowing down where reality stops matching what you expected.

Read the whole error message

This sounds obvious, and people skip it constantly. An error message usually names the type of problem, the file, and the line number. It often tells you almost exactly what went wrong: a value was empty when the code expected an object, a name was used before it was defined, a file wasn't found.

Read it slowly. Read all of it, not just the first line. If a word in it is unfamiliar, search for that exact phrase before touching anything.

Follow the stack trace

When an error prints a long block of file names and line numbers, that's the stack trace: the chain of function calls that led to the failure. The top is usually where the error was thrown. As you read downward, you move back through the calls that got you there.

The line you care about is often the first one that points at code you wrote, rather than a library or the language itself. Start there. That's where your assumptions and the program's behaviour parted ways.

Reproduce it before you fix it

A bug you can't trigger on demand is a bug you can't confirm you've fixed. Find the smallest, most reliable set of steps that makes it happen every time: this input, this button, this order of actions.

If it only happens sometimes, look for what varies between runs. Timing, an external service, a random value, leftover data from a previous run, the order that things load. Intermittent bugs are usually hiding one of those.

Narrow it down by halving

If you don't know which part of a stretch of code is misbehaving, check the middle. Print a value or add a breakpoint halfway through. Is the data correct at that point? If yes, the problem is in the second half. If no, it's in the first. Repeat, and you'll corner it in a few steps instead of squinting at everything at once.

The same idea works across versions. If the code worked last week and doesn't now, the cause is in what changed. Version control makes this concrete; git bisect will walk through past commits and help you find the exact one that introduced the problem.

Print what you actually need to know

Print debugging gets dismissed, but it's fast and it works. The trick is printing useful things:

  • The value of a variable right before the line that fails.
  • The type of that variable, not just its contents, since a string that looks like a number causes plenty of bugs.
  • A short label so you can tell which print is which.
  • A marker like "reached here" to confirm a block of code is running at all.

Once the bug is found, delete the prints. Don't leave them scattered through the file.

Learn the debugger

A debugger lets you pause the program on a chosen line, look at every variable at that moment, and step forward one line at a time. Most editors have one built in. It takes an afternoon to get comfortable with breakpoints, stepping, and inspecting values, and after that you'll reach for it instead of adding twenty print statements.

Check the thing you're sure about

When you've been stuck for a while, the bug is often in the part you've mentally ruled out. "That function definitely works." "That value is obviously set." Those are the assumptions worth testing directly, because if they were all correct, the bug wouldn't exist.

Explain it out loud

Describe the problem, step by step, to a colleague or to an object on your desk. The act of putting it into full sentences forces you to slow down, and people very often catch their own mistake halfway through the explanation, before the other person has said anything.

Change one thing at a time

When you think you've found the fix, make that single change and test it. It's tempting to adjust three things at once because you're fairly sure about all of them, but if the bug goes away you won't know which change did it, and if a new problem appears you won't know which one caused it. One change, one test, then move on.

Step away

If you've been staring at the same twenty lines for an hour, take a break. A short walk resets your attention, and the fix that was invisible at the desk often turns up on the way back. This isn't a trick; tired focus narrows what you can see.

Once the bug is fixed, it's worth adding a test that would have caught it. Bugs have a habit of coming back when someone later edits the same area, and a test that fails loudly is a much better warning than a user report weeks on.

The short version

Read the error. Follow the trace to your code. Reproduce the bug reliably. Cut the search space in half at a time. Print or inspect the values that matter. Question the assumption you're most confident about. Debugging well is mostly patience and method, and both improve with practice.

MA

Written by

Mark