I’ve had a copy of The Pragmatic Programmer (Hunt and Thomas) on my shelf for years but I’m finally reading through it in anticipation of teaching three programming-heavy courses this Fall. I just got to the section on Debugging and there are many tips in here that are helpful for reflecting on the mindset that novice programmers have as they start writing code and encountering bugs.
A few of the tips are classics: “Don’t panic” and “Don’t say it’s impossible” – I think of student queries about whether the compiler might be broken as off-shoots of the later of these two. And I’ve observed “Don’t panic” to be increasingly important advice as our OS’s and devices have trained us to simply click “OK” to make error messages go away as quickly as possible or have become smart enough to hide from us when errors are happening. But there are two deeper tips that I want to make sure to take into my classes.
First, “Resist the urge to fix just the symptoms you see”. Make sure you’re digging in to the root of the problem, not just making a fast, minimal change to correct the behavior for the one case you’re looking at. With introductory students, I often see this manifesting itself as what I call “flailing at their code” – switching around some ANDs and ORs and hoping it makes the problem go away rather than sitting down and understanding why the incorrect behavior is popping up. This is an easy habit to get into when the problems you are solving are simple. And changing a few things around to see what happens can be a good way to learn more about how your program (and programming language) function. But eventually you need to exercise the skill of being able to understand what your code will do before you compile and run it. I do a lot of live coding with students in my classes and I think it’s a great practice, particularly when students are taking the lead and you get to model not just solutions but the debugging that it takes to get to solutions. But I’ve started to also interrupt the live coding process and ask students to write out the line(s) of code to solve a small problem on a piece of paper. It seems to help slow some students down from a habit of just typing some code and seeing what happens rather than planning their problem solving and to highlight different types of issues than I see in the code they’re writing live in class. As an instructor bonus, I find it a lot quicker to walk around the room and glance over everyone’s shoulders to see what solution they’ve written down than to try to identify which portion of what is showing on everyone’s monitors is the bit I need to review.
The second deeper debugging tip relates to what we mean by “bugs” and isn’t a tip that Hunt and Thomas write about explicitly in their book. But, they do suggest turning up your compiler warnings as high as possible, because “It doesn’t make sense to waste time trying to find a problem that the compiler could find for you”. And, implicit in this is the fact that a compiler error isn’t a bug. For beginning students, it is easy for the goal to become “write code that compiles”. It’s certainly a base-line start and it’s often hard enough to do that. But debugging properly is about what you do after your code compiles and runs and it is very common for students to skimp on this part. There’s lots that can be done as an instructor to help students over this hurdle like providing or having students write unit tests, incorporating code review, modeling the debugging process during class, or giving every student a rubber duck. I give a first assignment in one of my classes that asks students to take a program that I’ve introduced errors in (both compiler errors and ones that will produce bugs) and correct them so the program has the correct output. It’s an assignment I’ll always include in the course because there are always students who stop when the compiler errors are gone and don’t identify the bugs in the program behavior. Because I let students resubmit the assignments, I can make sure that everyone’s gone back and practiced actual debugging before we get into harder content.