ChristCoded

the course / the basics

Debugging: the beam in your own code

"First cast out the beam out of thine own eye." When a program gives the wrong answer, the habit that helps most is the one Jesus taught about judging: look at your own part first. Learn to find a bug by printing what's inside, and to fix it one line at a time.

And why beholdest thou the mote that is in thy brother’s eye, but considerest not the beam that is in thine own eye? Or how wilt thou say to thy brother, Let me pull out the mote out of thine eye; and, behold, a beam is in thine own eye? Thou hypocrite, first cast out the beam out of thine own eye; and then shalt thou see clearly to cast out the mote out of thy brother’s eye. — Matthew 7:3–5 (KJV)

A mote is a speck of sawdust. A beam is a wooden plank. Jesus’ picture is meant to be a little funny: someone with a whole plank sticking out of their eye, leaning in to help with someone else’s speck.

He was talking about how we judge people, and that’s the first meaning of this passage. But the habit it teaches (look honestly at your own part first) is also the most useful habit a programmer can have.

The wrong answer

This program should add up the harvest: 12 + 9 + 15 = 36.

harvest = [12, 9, 15]
total = 0
for n in harvest:
    total = n
print("Total:", total)
Total: 15

There’s no error message. The program runs fine; it’s just wrong. This kind of bug is called a logic error.

It’s not Python’s fault

The first thought is usually “Python is broken” or “my computer is weird”. It almost never is. The computer did exactly what we wrote. So the bug is somewhere in our own lines, and that’s good news: it means we can fix it.

Look inside: print

You can’t see what a variable holds while a loop runs, so make the program tell you. Add a print inside the loop:

for n in harvest:
    total = n
    print(total)
12
9
15
Total: 15

Now we can see clearly. total isn’t growing; each time around, it’s replaced by the new number. The beam is total = n: it says “total is n”, not “add n to total”.

The fix

harvest = [12, 9, 15]
total = 0
for n in harvest:
    total = total + n
    print(total)
print("Total:", total)
12
21
36
Total: 36

total = total + n means: take the old total, add n, and store the result back in total. (Python has a shortcut for this: total += n.) Once it works, you can delete the print inside the loop.

When there is an error message

Sometimes Python does stop and tell you what’s wrong:

Traceback (most recent call last):
  File "harvest.py", line 5, in <module>
    print("Total:", totl)
NameError: name 'totl' is not defined

Read it from the bottom up: the last line says what went wrong (totl is a typo), and the line above it says where (line 5). The message is pointing at your own code. Take it as help, not as an insult.

The same idea in JavaScript

const harvest = [12, 9, 15];
let total = 0;
for (const n of harvest) {
  total = total + n;
  console.log(total);   // look inside
}
console.log("Total:", total);   // Total: 36

A debugging checklist

  1. Say what you expected (“36”) and what you got (“15”).
  2. Look at your own code first: the newest lines, the ones you just changed.
  3. Print the values you’re unsure about, inside loops and before ifs.
  4. Fix one thing, then run it again.
  5. Remove the extra prints when you’re done.

Common mistakes

  • Changing many things at once. If it starts working, you won’t know which change fixed it.
  • Not reading the error message, or reading only the first line. The last line matters most.
  • Assuming the computer is wrong. It does what you said, not what you meant.
  • Giving up on the first try. Every programmer debugs every day; it’s a normal part of the work, not a failure.

Try it

  1. This should count down from 3 to 1, but it never stops. Find the beam:

    n = 3
    while n > 0:
        print(n)
        n = n + 1
  2. This should print the average of the harvest (12), but prints 36:

    harvest = [12, 9, 15]
    average = sum(harvest)
    print(average)
    Answers
    1. n = n + 1 moves away from the end. Make it n = n - 1.
    2. It never divides. Use average = sum(harvest) / len(harvest), which gives 12.0.

Reflect

“Then shalt thou see clearly.” Jesus doesn’t say never help with the speck. He says take care of the beam first, and then you’ll see well enough to help. It’s an honest, humble way to treat people, and, it turns out, a good way to treat a program.