Skip to content
GetITechSkills

Logic and Programming

How to Debug Code Step by Step

Beginner · Skill · 7 min read · Updated October 30, 2026

Every program has bugs at some point, including programs written by experienced developers. A bug is a mistake in the code that makes the program crash or behave differently from what you intended. Debugging is the work of finding that mistake and fixing it. The skill has less to do with genius than with method. Guessing and changing things at random wastes time. Asking a series of small questions saves it.

This entry gives a step-by-step routine you can use in any language. The running example is a tip calculator that gives an absurd answer. Along the way you will see the three tools most people use: reading the error message, printing values, and using a debugger.

Start by reading, not changing

When something goes wrong, the first urge is to start editing. Resist it. Before touching the code, collect facts. There are three broad kinds of failure, and they feel different.

A syntax error means the code breaks the rules of the language, such as a missing bracket or colon. The program refuses to start, and the message points at the place where the problem was noticed. The real mistake is sometimes on the line just above.

A runtime error, also called an exception, happens while the program is running. Here is a small one:

tip = 6.0
print("Total: " + tip)

Python stops and prints a report, called a traceback, that ends with:

TypeError: can only concatenate str (not "float") to str

Read a traceback from the bottom. The last line names the kind of error (TypeError) and explains it in words: you tried to join text and a decimal number. The lines above it show which line of which file failed. Beginners often skip this message and stare at the code. The message is the cheapest clue you will get, so read every word of it.

The third kind of failure is the quiet one. The program runs without any error and gives a wrong answer. These are called logic errors, and they need the longest search because nothing points at them.

The step-by-step routine

Follow these steps in order. Each one narrows the problem a little.

  1. Describe the gap. Write one sentence: "I expected X, but I got Y." If you cannot say what you expected, you cannot tell that anything is wrong.
  2. Reproduce it. Find the exact input that causes the problem and make it happen on demand. A bug you can trigger every time can be fixed. One that appears at random must first be made predictable.
  3. Shrink the problem. Remove everything that is not needed to trigger the bug. A ten-line program that fails is far easier to study than a thousand-line one.
  4. Form a guess about the cause. Based on the evidence, pick one specific idea, such as "the percentage is being used as 15 instead of 0.15".
  5. Test the guess by looking at real values. Print them or use a debugger. Do not trust what you believe a variable holds.
  6. Fix one thing. Change one line, then run the same input again. If you change three things and it works, you do not know which one helped.
  7. Confirm and check around it. Try other inputs, including edge cases such as zero, and make sure you did not break something else.

A worked example: the tip that is too big

A restaurant bill is 40 and the tip should be 15 percent. This function seems fine:

def calculate_tip(bill, tip_percent):
    return bill * tip_percent

bill = 40
tip = calculate_tip(bill, 15)
print("Tip:", tip)
print("Total:", bill + tip)

It prints:

Tip: 600
Total: 640

Step 1, the gap. I expected a tip near 6 and a total near 46. I got 600 and 640.

Step 2, reproduce. The inputs are 40 and 15, and the wrong answer appears every time.

Step 3, shrink. The problem is already small. The suspect is the line inside calculate_tip.

Step 4, guess. The result 600 is exactly 40 times 15. So the function multiplies the bill by 15 and never turns 15 into a fraction.

Step 5, test with values. Print the inputs and see what the function receives:

def calculate_tip(bill, tip_percent):
    print(f"{bill=} {tip_percent=}")
    return bill * tip_percent

It shows bill=40 tip_percent=15. The guess holds. The function receives 15, and the formula never divides it by 100.

Step 6, fix one thing.

def calculate_tip(bill, tip_percent):
    return bill * tip_percent / 100

Run the same input again. Now the tip is 6.0 and the total is 46.0, which matches the expectation.

Step 7, confirm. Check other cases by hand. A bill of 0 should give a tip of 0.0, and a bill of 80 at 20 percent should give 16.0. Both are right.

Tools for looking inside

Adding temporary print lines is the simplest and most universal technique. Print the value of a suspect variable, or print a short note such as "reached the loop" to check that a section of code ran at all. Print the value and its name so the output is easy to read. Remove the extra lines when you are done.

A debugger

A debugger lets you pause the program and look around. In Python, you can write breakpoint() on the line where you want to stop. When the program reaches it, you get a prompt. Typing p bill shows the value of bill, n runs the next line, s steps into a function that is called, and c continues until the next stop. The official pdb documentation, listed in the sources below, covers the full set of commands. Code editors and browsers offer the same ideas with buttons instead of typed commands: set a pause point, step one line at a time, and watch values change.

A debugger is better than printing when you want to inspect many variables, or when you do not know in advance which ones matter. Printing is faster for a quick look. Learn both.

Rubber duck explaining

Explaining your code aloud, line by line, to a colleague or even to a toy on your desk forces you to state what each line really does rather than what you think it does. Many bugs show up in the middle of the explanation.

When you are stuck

If a long time passes with no progress, change the approach instead of repeating the same checks. Take a short break. Undo your recent changes and go back to the last version that worked. Search for the exact error message in the official documentation. When you ask someone for help, bring the full error text, the smallest code that fails, and what you already tried. That makes you easy to help. A habit that prevents a lot of this trouble is writing functions that are small enough to check one at a time, and a later entry on software testing basics shows how to automate those checks. For the wider picture of how code runs, start from what programming is.

Common mistakes

  • Changing code before understanding the problem. Random edits can hide a bug or create a new one. Gather facts first.
  • Ignoring the error message. It states the kind of problem and the line. Read it fully, starting at the bottom of a traceback.
  • Changing several things at once. You cannot tell which change mattered. Make one change per run.
  • Assuming instead of checking. "That variable must be 15" is a belief. Printing it is evidence.
  • Leaving debugging code behind. Stray print lines and breakpoint() calls can confuse users and slow the program. Remove them after fixing the bug.
  • Fixing the symptom, not the cause. Adding / 100 at the place where the result is printed would hide the problem for one case and break others. Fix the formula where it lives.

FAQ

Why is it called a bug?

The word was used for technical faults in machines long before computers. In software it simply means a mistake in the code or design. The name does not matter for the method.

Are errors a sign that I am bad at programming?

No. Experienced programmers meet errors every day. What improves with practice is how quickly you read the message and narrow down the cause.

What is the difference between an error and an exception?

In Python, an exception is an error detected while the program runs. Syntax errors are detected before it runs. Many beginners use "error" for both, and that is fine in conversation.

Should I use print statements or a debugger?

Use whichever answers your question fastest. Print statements are quick for one or two values. A debugger helps when the program is bigger or you need to step through logic.

How can I make bugs less likely?

Write small functions, give variables clear names, and test with simple inputs as you go. The Logic and Programming area has more entries that build these habits.

Sources

  1. Errors and Exceptions (The Python Tutorial) (opens in a new tab) — Python Software Foundation (docs.python.org). Explains syntax errors, exceptions and how to read them
  2. pdb: The Python Debugger (opens in a new tab) — Python Software Foundation (docs.python.org). Official reference for breakpoint(), stepping and inspecting values

Next in Logic and Programming: What Is an Algorithm? Everyday Words and Pseudocode

  • Logic and Programming

    What Is Programming? A Simple Introduction

    Programming means writing exact instructions for a computer. Learn what code is, how a program runs, and what a first small program looks like.

    • Beginner
    • Concept
    • 7 min read

    Updated October 30, 2026

  • Logic and Programming

    Software Testing Basics: Why Unit Tests Matter

    Learn what a unit test is, how to write and run one with Python's unittest, how to pick test cases, and why small automated checks catch bugs early.

    • Intermediate
    • Skill
    • 7 min read

    Updated October 30, 2026

  • Logic and Programming

    Functions Explained: Reusable Pieces of Code

    A function is a named block of code you can run again and again. Learn parameters, return values, scope and why functions keep programs tidy.

    • Beginner
    • Concept
    • 6 min read

    Updated October 30, 2026