Chapter 13

Fixing Problems by Debugging

IN THIS CHAPTER

check Finding and reading error messages

check Tracking down common bugs

check Debugging strategies

Bugs have been causing coders headaches and frustration for decades. Coders spend upwards of 50 percent of their time debugging — fixing errors in their code, and not just writing code! This is part of what makes coding so “hard.” It’s not impossible to figure out — it just takes persistence when the computer is telling you you’re wrong.

You can encounter two different kinds of coding bugs: syntax bugs and semantic bugs. Syntax bugs are ones where you have written something incorrectly. Maybe you spelled a variable wrong, or you forgot a semicolon at the end of your line of code. These bugs are often easy to fix and result in your programming environment displaying an error message to you. Semantic bugs are ones where your logic is incorrect. For example, you’re iterating through a list of five numbers and you try to access the sixth element, or you’re checking to see whether variable1 is less than variable2 in an if-then statement, but you accidentally write variable1 > variable2. These bugs are often harder to find because they require you to test your code and see what happens, and then trace your code to find where the error is located.

When teaching and guiding young coders through their coding journey, it's important to help them understand that errors, bugs, and mistakes in coding are normal and expected. Performing the debugging process is a huge part of being a coder, and learning strategies, patience, and persistence is critical to coders if they are to succeed in their coding adventures.

If you haven’t heard of the infamous Admiral Grace Hopper and how she coined the term “bug” for an error in a computer program, you should definitely read the sidebar about her in Chapter 5!

Debugging, Unplugged

Teaching your young coder about debugging is also about teaching her that computers are very precise. When we’re introducing this concept to young coders, we like to present them with the following scenario: If I told you to go to your shoes and put your room on, you could probably figure out that I meant to say go to your room and put your shoes on. But if I were to tell a robot to go to its shoes and put its room on, it would literally walk over to its shoes and then try to put its room on…which is impossible! And it would probably tell you that it cannot complete the action, or maybe even try so hard to “put its room on” that it just crashes.

As a fun activity to do with a group of young coders, you can play a game of “Describe the Picture.” In this game each person is given a unique picture drawn on a grid. Each person keeps his picture hidden from his partner. Then, each person is given a blank sheet of grid paper.

In one version of the game, each partner takes a turn describing his picture to his partner using only descriptive language (not showing them the image). He has five minutes to describe the picture while his partner tries to re-create it on the grid paper. Then they switch who is describing and who is drawing. At the end of the ten minutes they show each other their drawings. Most of the drawings will be incorrect, and at that point you can talk about what went wrong and how hard it is to be precise!

In another version, you can add an element of debugging to the end of the game. Rather than describing the picture to their partners, each person writes a series of steps that his partner should follow to re-create the picture. For example, if a coder is given the picture shown in Figure 13-1, then he has these steps to re-create the picture:

  1. Draw a rectangle at the top center of the page.
  2. Draw another longer rectangle underneath that rectangle.
  3. Draw a circle under that rectangle.
  4. Draw another, bigger circle under that circle.
  5. Draw another, bigger circle under that circle.
image

FIGURE 13-1: An example of a picture on a grid to re-create in an unplugged activity.

However, based on these steps, his partner could also create the image shown in Figure 13-2. After each partner completes their steps and draws their partner’s drawing, they can work together to improve their list of steps — essentially debugging the error in their steps. For example, partners may decide that adding specifics such as “below,” “touching but not overlapping,” and, “with centers aligned along the y-axis” may improve their instructions.

image

FIGURE 13-2: An example of what the partner might draw based on imprecise instructions.

Finding Common Syntax Errors

One of the hardest parts about debugging is finding where the program is displaying the errors in your code, and then interpreting them. Each programming language and coding application has slightly different ways of displaying and describing error messages. This section gives some examples of error messages that you might see in different programming languages, where to find them in an example application, and how to interpret them.

Scoping errors

A scoping error is one where you’ve created a variable and you try to access the variable, but the part of the code that you are in doesn’t know about it. Scopes can be described by looking at what is between curly braces, or within the “mouth” of a block-based language. For example, if you write a for loop in Java it would look like this:

for(int index = 0; index < 10; index++)

{

System.out.println(index);

}

The index variable only lives within the scope of the for loop. So that means, when you print the index variable within the curly braces of the for loop, the computer knows what variable you want to print, and can accurately print it. However, if the code looked like this:

for(int index = 0; index < 10; index++)

{

System.out.println("In scope:" + index);

}

System.out.println("Out of scope:" + index);

The line that tries to print the index that is outside of the curly braces would throw a scoping error. The error in Java would be:

java:lineNumber: error: cannot find symbol

System.out.println("Out of Scope: " + index);

^

symbol: variable index

location: class className

1 error

This error would appear when you try to compile your Java code.

Though it's pretty difficult to get a syntax error in block-based languages because the blocks are already created for you, it’s possible to get a scoping error. For example, in App Inventor, you could create a local variable called myName and set a label to that variable. However, if you only had one variable that was local, and you tried to set a label to that variable outside of its own “mouth,” it would show a scoping error — there would be no variables available for that block. Figure 13-3 shows an example of this error in App Inventor.

image

FIGURE 13-3: An example of a scoping error in App Inventor.

Typing errors

Typing errors can happen to the best of us! Especially for young coders who don’t have a lot of experience typing on a keyboard, or who may not be the best spellers, typing errors can be fairly common. Common typing errors are misspelling variables and methods, but another type of typo can be mis-capitalization. For example, in a simple Python program that assigns a value to a variable, and then attempts to print the variable:

myName = 'Sarah'

print (myname)

The error is that the variable has camelCasing when it’s defined, but then has only lowercase when used in the print function. The error you would get if you ran the program would be:

Traceback (most recent call last):

File "example.py", line 2, in <module>

print myname

NameError: name 'myname' is not defined

Scratch, on the other hand, is a language that really tries to protect the user from typing errors. For example, Figure 13-4 shows a simple program; it’s impossible to make the same error as you can with Python (mis-capitalizing the variable name), because you don’t re-type the variable names each time with Scratch; you simply use the variable block that is created when you first created the variable. But a potential mis-capitalization is checking the value of the variable. Notice that the value was set to Sarah, but the if-then statement checks to see whether the value was sarah. In a language such as Python or Java this error would make the if-then condition evaluate to false, but in Scratch it evaluates to true, making the sprite say “Hello there!” when the green flag is clicked.

image

FIGURE 13-4: An example of a typing error in Scratch that is caught by the app.

tip When you're coding and you run into an error that identifies a variable that is unknown, check spelling and capitalization!

Incorrect data types

Another syntax error to watch out for is using incorrect data types. This can happen only in strongly typed programming languages, like Java. For example, say you had the following program:

int month = "11";

int day = "15";

System.out.println("My birthday: " + month + "/" + day);

The errors that you would get when compiling your program is:

java:lineNumber: error: incompatible types: String cannot be converted to int

int month = "11");

^

java:lineNumber: error: incompatible types: String cannot be converted to int

int day = "15");

^

2 errors

Usually the error messages regarding incorrect data types are straightforward; however, understanding what data types are the correct ones to use can be a tricky subject for young coders. For example, the error messages in the code example indicate that the coder attempted to assign a string type (11 and 15 are strings because they have quotation marks around them) to a variable that is an integer type, which is a number.

Finding Common Semantic Errors

Unlike syntax errors, semantic errors are often more difficult to capture. This is because semantic errors are typically errors in the programming logic, rather than something that you typed incorrectly. This section has a couple of examples of semantic errors that you and your young coder might encounter in a few different programming languages.

Infinite loops

Infinite loops are loops that never end! They go on infinitely. This can be a problem because it might seem like the code just isn't working, but really the program is just running forever and ever.

Using Java

If you wrote a small Java program where you wanted to print the numbers 0 through 9, you might write something like this:

for(int index = 0; index < 10; index--)

{

System.out.println(index);

}

But there is an error in this code! Instead of updating the index to be index + 1, the code updates the index to be index – 1! So the code does the following:

index = 0

Is index < 10? Yes

Print index 0

index = index – 1 index = -1

Is index < 10? Yes

Print index -1

index = index – 1 index = -2

Is index < 10? Yes

Print index -2

index = index – 1 index = -3

Is index < 10? Yes

Print index -3

This continues forever, because it’s impossible for index to be greater than or equal to 10. So when you run the Java code, the program continues to print forever, until you kill the program!

Using Scratch

Although infinite loops can be a problem, some programming languages deliberately have implemented infinite loops to make some pretty neat effects! For example, in Scratch there is a forever block. Figure 13-5 shows two programs that are very similar. The left figure shows a program that checks to see whether the mouse pointer is touching the sprite. If it is, then the sprite meows. The problem is that the if-then block is checked only once — at the moment when the green flag is pressed — and it’s never checked again. The right figure shows the same program, but with a forever loop block around the if-then block. Now, after the green flag is clicked, the if-then block keeps asking, forever, whether the mouse pointer is touching the sprite. This makes it a program that always makes the sprite meow when the mouse pointer touches it until the red stop sign is pressed (which is the same as killing the program).

image

FIGURE 13-5: An example of a Scratch program that doesn’t do what is intended because there is no forever loop (left); an example of a Scratch program benefiting from infinite loops (right).

Off by one

Another very common error to run into is called an off by one error. This is very common when dealing with lists and iterating through lists. For more information about lists, check out Chapter 11.

Using Scratch

Scratch, as usual, handles off by one errors for the user without really indicating there’s a problem. For example, Figure 13-6 shows a program that loops through a list of pets and has the sprite say Hi petName, where petName is replaced with the item from the list (either Luke, Winston, or Princess). The loop repeats four times, but there are only three items in the list. Instead of completely breaking, on its last iteration, Scratch prints Hi with nothing after it (as shown in Figure 13-6).

image

FIGURE 13-6: An example of a Scratch program with an off by one error.

Using Python

Other programming languages are not as forgiving. For example, in Python you might have the following program to say hello to the three pets:

pets = ['Luke’, 'Winston', 'Princess']

for x in range(1, 3):

print (‘Hi ‘ + pets[x])

If you run this program, the output would be:

Hi Winston

Hi Princess

The reason ‘Hi Luke’ doesn’t print is because lists in Python start at 0, not at 1. The correct code would be:

pets = ['Luke', 'Winston', 'Princess']

for x in range(0, 3):

print ('Hi ' + pets[x])

technicalstuff If you’re confused by any of the Python list examples, make sure to check out Chapter 11. For example, the range function used in Python:

range(0, 3)

Represents the elements 0, 1, and 2 because the range function includes the first number but excludes the second.

Another version of an off by one error in Python would be if you went beyond the length of the list. For example:

pets = ['Luke', 'Winston', 'Princess']

for x in range(0, 4):

print ('Hi ' + pets[x])

This causes even more of an issue, because instead of simply missing an element in the list, you’re trying to access an element that never existed in the first place. The output for running this code is:

Hi Luke

Hi Winston

Hi Princess

Traceback (most recent call last):

File "filename.py", line 4, in <module>

print ('Hi ') + pets[x]

IndexError: list index out of range

There is an actual error, because the data for pets[4] doesn’t exist, so the computer cannot resolve it; therefore it doesn’t know what to do.

remember Off by one errors can be really tricky for young coders, especially if they’re switching between languages where lists start at 1 versus lists that start at 0.

Strategies for Debugging

When you and your young coder are trying to debug, sometimes no error messages give you insight into the problem. This section has a list of strategies for debugging programs where you don’t get an error message, or the error message doesn’t give you enough information.

Turning sections on and off

One of the best ways to debug is to disable sections of code so that you have small sections to test.

Using Scratch

In Scratch, you might have a lot of scripts that start when the green flag is pressed. This can cause problems if some of the scripts cancel out or affect the other scripts. For example, Figure 13-7 shows three scripts associated with one sprite. The problem that the user notices is when the mouse pointer is touching the sprite, it does not meow. To try to figure out the problem, the coder might disconnect all the scripts and only have one script connected at a time, like in Figure 13-8. Then they see that the code for the mouse pointer touching the sprite works correctly, but that there is another problem (the code that stops all sounds forever). By connecting and disconnecting the blocks, the coder can identify the problem.

image

FIGURE 13-7: An example Scratch program.

image

FIGURE 13-8: An example of turning off sections in Scratch to identify a bug.

Using App Inventor

Other block-based languages like App Inventor make turning sections on and off even easier! For example, in Chapter 15 there is a Puppy Play Day mobile game that you can create. Figure 13-9 shows how if you right-click a code block, you can disable that block. In this example, you might want to make sure the initial property settings work before creating the lists and hiding the items. Then, after you confirm the properties are set properly, you can enable the call to setupLists to make sure that works. Then you can enable the call to hideItems to make sure that works.

image

FIGURE 13-9: An example of turning off sections in App Inventor to identify a bug.

remember By turning off all sections and then turning each one on one at a time, it’s easier to find bugs.

Using Python

Text-based languages have a similar way of turning sections on and off — you only have to comment out the lines of code. In Python, you can comment out a single line of code like this:

#print 'Hi'

And you can comment out multiple lines of code like this:

"'

for x in range(0, 4):

print ('Hi ' + pets[x])

"'

Commenting out code is how you “turn off” or “disable” parts of your code when you’re in a text-based language.

Testing sample data

A common bug that coders run into is not testing data to make sure that the program works. This can especially be a problem if you’re writing programs that take user input. It’s important to make sure you and your young coder think about what kind of input you’re expecting, and test to make sure the input is handled correctly.

You might have a program that gets input from the user and prints what the user types, like this Python code:

name = raw_input('What is your name? ‘)

print (‘Hi ' + name)

It’s important to test to make sure that if you put the following types of input, they still do what you, as the coder, expect:

Sarah

Sarah Guthals

13

11/15

Sarah 55 Guthals

By mixing letters, spaces, numbers, and other symbols like / you’re ensuring that your program performs as expected. This type of testing is unit testing and ensures that small portions of your program execute correctly with varying input.

Adding output messages

One of the most challenging aspects of coding is that the code is abstract and sometimes the data is hidden. This is especially tricky when you have complex data or are performing complex operations on data. By adding a number of output messages in your code, you can indicate when certain sections of code have been reached, or you can show the current values of certain variables at various points during execution.

An example of adding output messages to a program to gain insight in Python follows. Here, your goal is to write a program to solve an algebraic expression. For example:

x = input('Provide a number for x: ')

y = input('Provide a number for y: ')

first = 2*x

second = 6*y

sum = first - second

print '2x + 6y = '

print (sum)

There is an error in this program; instead of adding the first and second elements, the coder is accidentally subtracting. Though this error is fairly obvious because this example is small, it shows how a simple typo could completely change the output. If you run this code, you get results like:

Provide a number for x: 2

Provide a number for y: 3

2x + 6y =

-14

This is clearly wrong. 2*2 + 6*3 = 4 + 18 = 22, not -14. One way of debugging this code is to add output messages at each point. For example, you could change your code to:

x = input('Provide a number for x: ')

print ('x: ')

print (x)

y = input('Provide a number for y: ')

print ('y: ')

print (y)

first = 2*x

print ('first: ')

print (first)

second = 6*y

print ('second: ')

print (second)

sum = first - second

print "2x + 6y = "

print sum

Then, when you run the code you get the following output:

Provide a number for x: 2

x:

2

Provide a number for y: 3

y:

3

first:

4

second:

18

2x + 6y =

-14

Then the coder can see that x, y, first, and second are all correct. This must mean that it’s just when the sum is calculated that there is an error.

Walking Away

Although there might be other ways to debug for different languages and programming environments, one universal strategy is to walk away from your code. Sometimes, when you stare at the same code for hours, you just aren’t seeing the obvious problems. By walking away from your program and giving yourself a 20-30 minute break, you can gain perspective. One of Sarah’s professors liked to call this the Gilligan’s Island strategy because he would walk away and watch an episode of Gilligan’s Island before returning.

Many expert coders can tell you stories of how they worked on debugging a program for over 5 hours, they went home and went to bed, and when they woke up they knew exactly what the problem was and were able to fix it in a matter of minutes. Camille finds that walking her dog, Pepper, unclutters her own thinking and allows her to approach the problem with fresh eyes and a clear mind. This isn’t magic. It’s letting your brain relax and approach the problem in another way.

remember For a lot of young coders, walking away from a problem can be really difficult. They don’t want to give up and they are already frustrated because the program isn’t working as they expected. When frustrated, this is the most important time to walk away.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.237.255