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:
Enter 0 for the number of years. Click the Calculate button. 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:
Don't be afraid to rewrite code. In many cases the best way to
fix overly complicated code is to rearchitect the system and start
from scratch. Recreating a program nearly always goes faster and
smoother than creating the program in the first place. Most experts
agree on this one (for example, Quake III was a complete rewrite of
the Quake II engine). That said, new code still needs to be debugged.
Don't throw out perfectly good code close to a deadline. Keep
what's good and rewrite only the problematic code. Break problematic components out into separate test movies. Work on
each aspect of a system in complete isolation, then integrate working
sections one at a time. Have a peer review your code. Don't be afraid. We're all
embarrassed by the code we wrote a year earlier. Ask for help at one of the resources cited in Appendix A, "Resources". For example, the FlashCoders mailing list is
devoted entirely to ActionScript questions.
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).
 |  |  | | 19. Debugging |  | 19.3. Onward! |
Copyright © 2002 O'Reilly & Associates. All rights reserved.
|
|