Book HomeActionScript: The Definitive GuideSearch this book

19.2. Debugging Methodology

Let's take a quick look at some techniques involved in code debugging. Debugging can be broken into three stages:

19.2.1. Recognizing Bugs

Very often, we recognize code problems as part of the active process of programming. That is, we write some code, test our movie, and find that the movie doesn't work properly. Problem recognized.

The earlier a problem is discovered, the better. The process of writing code should therefore be a constant ebb and flow of writing and testing -- write a few lines, export the movie, make sure the lines work as expected, then write a few more lines, export the movie, and so on. Make sure each component of a program works on its own before testing the program as a whole. Try not to get carried away writing a complex body of code without testing it frequently along the way.

Don't assume your movie is perfect just because you can't find any bugs on your own. Always schedule time for external testing by target users, particularly if the code you are delivering is part of a product or a service intended for a client. As described earlier, implement error checking to head off possible problems with incorrect data input. For example, if you write a function that expects an integer argument, you might use the typeof operator to verify that the input parameters are of the correct type. Also test end conditions such as extremely large, small, and negative values, including zero.

Don't underestimate the value of finding the minimum reproducible steps that replicate the problem. These should be the fewest steps that recreate the error reliably. A bug report such as, "I played it for an hour and then it froze" is not very helpful. Useful bug reports include numbered steps such as:

  1. Enter 0 for the number of years.

  2. Click the Calculate button.

  3. The results field shows "NaN" instead of a dollar amount.

19.2.2. Identifying the Source of a Bug

Once we've recognized a bug, our quest for a solution has only begun. Our first task is to find the source of the bug, however far upstream that may be. A bug can be thought of like a heart attack that was caused by bad dietary habits years earlier. The heart attack is merely the most manifest symptom, but you must often correct something earlier in the process. Most bugs are caused by false assumptions; we assume we've typed the name of a variable correctly but we haven't, or we assume a text field stores numeric data but it doesn't. By executing a series of trace( ) statements or using the Debugger or List Variables command, we can test our assumptions against the interpreter's understanding of our code.

Here, for example, is some code with a bug. It incorrectly sets status to "equal":

var x = 11;
isTen(x);
function isTen(val) {
  if (val = 10) {
    status = "equal";
  }
}

To find out what's wrong with the code, we compare what we think the code should be doing against what it actually is doing, one step at a time:

// This should set x to 11
var x = 11;

// Let's see if it really does
trace(x);     // Yup...this displays: 11

// This should invoke the isTen( ) function
isTen(x);

// Now on to our function
function isTen(val) {
  // Let's make sure our function is being called
  trace("isTen was called");    // Yup...this displays: "isTen was called"

  // Now let's make sure our parameter was passed correctly
  trace("val is " + val);       // Yup...this displays: "val is 11"

Let's pause here for a second. Notice what's happened -- we've made it most of the way through our code and so far everything has worked as expected. Our variable was set correctly; isTen( ) was called and received its argument properly.

TIP

Many errors occur because the code that you think is being executed has never even been reached! We can use trace( ) statements to verify that a particular portion of our code is reached.

By process of elimination, we already know that our code's problem must lie either in the conditional statement if(val = 10) or in the text field assignment status = "equal". We next check our conditional statement by using trace( ) to display the value of its test expression (we're expecting either true or false):

trace(val = 10);

Eureka! The Output window displays 10, not true or false as we had expected.

On closer inspection, we see that the test expression is an assignment statement, not a comparison statement! We forgot an equal sign in our equality comparison operator. The expression if(val = 10) should be if(val == 10).

Obviously, not all bugs are as simple as our conditional statement bug (which is an exceedingly common error), but the approach we used is applicable to most bug hunts: execute a series of trace( ) functions to create a running, step-by-step report on the actual behavior of a movie's code and use the Debugger as explained in the Macromedia documentation.

19.2.3. Common Sources of Bugs

Table 19-1 lists some common sources of bugs in ActionScript.

Table 19-1. ActionScript Gotchas

Problem

Description

Code in the wrong place

All code must be attached to a movie clip, frame, or button. Take care that your code is actually attached to what you intend by observing the title of the Actions panel -- when attaching code to a frame, the Actions panel's title reads Frame Actions; when attaching code to a movie clip or button, the Actions panel title reads Object Actions. If you want a script to be on a particular frame, make sure that frame is selected in the timeline before you start coding, and that there's a keyframe where you want to place your code. If you want a script to be on a movie clip or button, make sure that object is selected on stage before you start coding. Use the Movie Explorer (Window Movie Explorer) to keep track of exactly where code is attached.

Missing event handler

Code attached to movie clips and buttons must be contained by an event handler. For movie clips, use:

onClipEvent (event) {

// statements

}

For buttons, use:

on (event) { 
    // statements
  }

where event is the name of the event to handle. The error, "Statement must appear within on handler," indicates that you're missing an event handler. See Chapter 10, "Events and Event Handlers".

Bad movie clip reference

A movie clip that doesn't exist is referenced, or a reference to a movie clip is malformed. Check that all instances are named, and that instance names match the reference supplied. See Section 13.5.3, "Referring to Nested Instances" in Chapter 13, "Movie Clips" for information on composing valid movie clip references.

Unexpected type conversion

The result of a data conversion yields an unexpected result. For example, 3 + "4" yields the string "34", not the number 7. Similarly, the string "true" converts to the Boolean value false! Study type conversion rules in Chapter 3, "Data and Datatypes". Check datatypes using the typeof operator.

Missing semicolon

A statement ends prematurely because a semicolon is missing. See Chapter 14, "Lexical Structure" for proper semicolon usage.

Problem quotation mark

A string includes an unescaped quotation character that interferes with the string literal. See Section 4.5.2, "String Literals" in Chapter 4, "Primitive Datatypes".

Bad text field data usage

A text field is treated as a number or other datatype, not a string. User input in text fields is always a string value and should be converted manually before being treated as any other type.

Scope problems

A variable, property, clip, or function is referenced in the wrong scope. For example, a statement in a clip handler attempts to invoke a function scoped to that clip's parent timeline. See Section 10.7, "Event Handler Scope" in Chapter 10, "Events and Event Handlers", Section 2.5, "Variable Scope" in Chapter 2, "Variables", and Section 9.6, "Function Availability and Life Span" in Chapter 9, "Functions".

Global function versus method confusion

Some global functions have the same name as movie clip methods. Occasionally, this overlap causes problems. See Section 13.8.3.1, "Method versus global function overlap issues", in Chapter 13, "Movie Clips".

Content not yet loaded

A reference to a clip, property, function, or variable can't be resolved because the content is not yet loaded. Be sure all content is loaded by checking the MovieClip._framesloaded property as shown in Part III, "Language Reference".

Incorrect capitalization

Some keywords are case sensitive in ActionScript. If you mis-capitalize onClipEvent as onclipevent, ActionScript will think you are trying to call a custom function named onclipevent instead of using the built-in onClipEvent handler keyword. As such, it will give you an error when it encounters the { at the beginning of the onClipEvent statement block (it expects a semicolon indicating the end of what it perceives to be an onclipevent function call). See Section 14.6, "Case Sensitivity" in Chapter 14, "Lexical Structure".

19.2.4. Fixing Bugs

In some cases, the fix for an identified bug is self-evident. For example, if we discover a bug caused by a missing quotation mark on a string, we fix the bug by adding the quotation mark.

In more involved programs, fixing bugs can be a serious challenge. If a bug is proving difficult to fix, consider the following:

For lots of good advice on programming techniques, see Extreme Programming Explained by Kent Beck (Addison Wesley) and Code Complete by Steve McConnell (Microsoft Press).



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.