Writing Code That Is Easy to Debug
Debugging is the process of finding the cause of an error in your code, triggered by error messages or incorrect results.
When Investigation Begins
Debugging is the process of finding the cause of an error in your code. You need it when Python reports an error message or when your program runs but produces an incorrect result. A program does not have to crash to contain a bug: incorrect output is also a reason to investigate.
Debugging is not a random hunt in which you change several lines and hope the result improves. It is a systematic process. You gather information, compare the program with your intention, test focused changes, interpret what happens, and restore clarity when your experiments become confusing.
Reading the Intended Logic
Reading is often the first and fastest debugging strategy. Examine the code carefully and compare what it actually does with what you intended it to do. Read it aloud or trace it line by line. Simple mistakes such as a misspelled variable name, a reversed comparison operator, a missing colon, or logic that differs from your intention can become visible during this comparison.
Comparing an Algorithm with Its Implementation
A programmer intends an algorithm to check each item, keep the items that meet a condition, and then report the resulting collection. The output does not match the expectation.
State the intended steps: Write down the logic in plain language: examine each item, test the condition, keep matching items, and report them.
Trace the actual code: Follow the program line by line and note what each operation actually does. Do not assume that a line expresses the intended step merely because it looks similar.
Compare the two descriptions: Look for a difference such as a reversed condition, a skipped item, or a result being reported before all items have been examined.
Correct the mismatch: Change the part that differs from the intended logic, then verify the behavior again.
The reading strategy finds a logic error by comparing intention with behavior, rather than by changing several parts of the program at once.
Reading is especially useful for a simple bug. Before adding temporary display code or making experimental changes, check whether the code says what you think it says.
Running Focused Experiments
When careful reading does not reveal the problem, use the running strategy. Make a small, deliberate change and observe the result. Temporary display code, sometimes called scaffolding, can show the values held by variables or the intermediate results produced at different points. This evidence helps narrow down where the problem occurs.
Narrowing Down an Incorrect Result
A program produces an incorrect final result, but reading the code has not shown the cause.
Observe an intermediate value: Add temporary display code after an early calculation to see whether the first stage produces the expected value.
Interpret the location: If the intermediate value is already wrong, investigate the earlier calculation. If it is correct, leave that part alone and examine a later stage.
Test one focused change: Change one calculation or condition and run the program again. Record whether the output changes and how it changes.
Remove or revise scaffolding: Use the temporary information to locate the problem, then keep the useful correction rather than leaving unrelated experimental code in place.
Running turns an unclear problem into a sequence of observations. Each experiment supplies information about where the behavior begins to differ from what was expected.
Ruminating on Evidence
Ruminating means stepping back and thinking analytically about the problem. Use your understanding of Python, the observed behavior, the error message, and the changes you made recently. The goal is to connect the symptom with a plausible cause instead of reacting to it randomly.
| Error type | What it means | Useful question |
|---|---|---|
| Syntax error | The code does not follow Python's grammar rules. | Which part of the code violates the language's required form? |
| Runtime error | The code is grammatically correct, but something goes wrong while Python executes it. | What operation fails during execution? |
| Semantic error | The code runs without crashing but produces the wrong result because the logic is incorrect. | Which part of the logic differs from the intended result? |
Error categories guide the questions you ask during debugging.
Read error messages carefully. They often indicate what went wrong and where. Also review your most recent change, because a bug often appears shortly after a modification. Ask: What kind of error could produce this exact symptom? What did I change that could cause it?
Retreating to Clarity
Sometimes experimentation creates a second problem: you have made so many changes that you no longer know what changed, which changes helped, or which changes caused new behavior. At that point, retreating is the sensible strategy. Undo the recent changes and return to a version of the program that you know works.
Retreating is not giving up. A known working state gives you a clear starting point. From there, make changes carefully, test each one separately, and keep track of what happens. This reduces the confusion created by layers of experimental changes and makes it more likely that you will find the real problem.
Choosing the Next Strategy
Reading, running, ruminating, and retreating are not fixed steps that every bug must pass through. They are tools. A simple bug may be solved by reading alone. A complex bug may require reading, experiments, analysis, and then retreating if the experiments become confusing. You can move between the strategies as new information appears.
- Start with reading because it is fast and often reveals a simple mismatch between intention and code.
- Use running when reading does not show where the behavior changes. Add temporary display code and test one change at a time.
- Use ruminating when experiments produce information but the cause is still unclear. Classify the error, inspect its message, and consider recent changes.
- Use retreating when accumulated changes have made the program difficult to understand. Return to a known working state and begin again more deliberately.
Changing several parts of the program at once
The programmer cannot tell which change fixed the problem or caused a new one.
Fix:
Change one thing at a time and observe the result.Assuming that a program is correct because it does not crash
A semantic error can let code run while producing an incorrect result.
Fix:
Treat an incorrect result as a debugging signal and compare the logic with the intended behavior.Ignoring the error message
The message often provides information about what went wrong and where.
Fix:
Read the message carefully and use the error type to guide the investigation.Continuing to add changes after losing track of the program
Layers of untracked changes make the cause harder to identify.
Fix:
Retreat to a known working state, then test new changes deliberately.
Practice the Debugging Cycle
Imagine that a program produces an incorrect result and no obvious mistake appears during the first reading. Describe what you would do next using the four strategies. Include the temporary information you would seek, the error questions you would ask, and the point at which you would retreat.
Hints
- Begin with a small experiment rather than several unrelated changes.
- Use temporary display code to inspect an intermediate value.
- Consider whether the symptom suggests a syntax, runtime, or semantic error.
- Retreat if you can no longer explain which changes produced the current behavior.
A Complete Strategy Choice
A program runs but reports an incorrect answer. The programmer has already made several experimental changes and no longer knows which version was reliable.
Retreat: Return to the known working version instead of adding more untracked changes.
Read: Compare the intended algorithm with the restored code line by line.
Run: Make one focused change or add temporary display code to inspect an intermediate result.
Ruminate: Interpret the observed result, consider that an incorrect answer may be a semantic error, and review the most recent change.
The strategies work together: retreat restores clarity, reading checks the logic, running gathers evidence, and ruminating connects that evidence with a likely cause.
Key Takeaways
- Debugging finds the cause of an error, whether the program reports a message or produces an incorrect result.
- Reading compares the code's actual logic with the programmer's intended logic.
- Running uses small experiments and temporary display code to narrow down where a problem occurs.
- Ruminating uses error types, messages, and recent changes to reason about root causes.
- Retreating restores a known working state when accumulated changes have made the program confusing.
Key Takeaways
- Debugging is a systematic investigation triggered by an error message or an incorrect result.
- Begin by reading the code against the intended logic, then run focused experiments when necessary.
- Use error categories, messages, and recent changes to reason about possible causes.
- If experimentation creates confusion, retreat to a known working state and restart carefully.