Low-level Debugging in J2ME

2007-03-31

Scope of Article

Debugging MIDlets can be challenging to say the least. This article
aims to show programming techniques that can reduce the need to debug and then best practices when debugging as well as the top tool for that task.

Debugging as is commonly done in J2SE with breakpoints is not discussed as it is not always available in J2ME. In other words the reader is assumed to have working knowledge of System.out.println() method.

Preventative VS Corrective Maintenance

“An ounce of prevention is worth a pound of cure” certainly rings true when developing applications for mobile devices. When creating a class or method it is worth creating an accompanying Unit Test (UT) which can expose any flaws early in the development process. JUnit (bundled with the Eclipse IDE) and J2MEUnit are two testing frameworks that perform tests on the development host PC and the target device respectively. Unit testing deserves an article all by itself and cannot be done justice here, but certainly keep it in mind if you’re aiming for robustness.

Developing Defensively

Applications invariably fail from time to time. The reason is often human error. As applications grow bigger and bigger their complexity becomes a thriving environment for bugs. It has been the goal of many programming languages to reduce these complexities through enhancing expressiveness (accomplishing tasks in fewer instructions/steps).

For this reason a line of hand-written Java code is less likely to contain a bug then its assembly language equivalent. However expressiveness alone is not enough to keep our applications bug-free. It also helps to program defensively where assertions are sprinkled around the code like traps waiting for bugs. A simple example is that of validators at the beginning of key methods.

Defenseless method


void setAge(int age) {
    this.age = age;
}

Defensive method


void setAge(int age) {
    if (age < 0) {
        StringBuffer msg = new StringBuffer();
        msg.append("The negative age (");
        msg.append(age);
        msg.append(") is not permitted.  age must be 0 or higher.");
        throw new IllegalArgumentException(msg.toString());
    }

    this.age = age;
}

Defenseless method


void setDayOfWeek(int dayOfWeek) {
    this.dayOfWeek = dayOfWeek;
}

Defensive method


void setDayOfWeek(int dayOfWeek) {
    switch (dayOfWeek) {
    case SUNDAY:
    case MONDAY:
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
    case SATURDAY:
        break;
    default:
        StringBuffer msg = new StringBuffer();
        msg.append("The dayOfWeek (");
        msg.append(dayOfWeek);
        msg.append(") is not recognized. dayOfWeek must be one of ");
        msg.append("SUNDAY, ");
        msg.append("MONDAY, ");
        msg.append("TUESDAY, ");
        msg.append("WEDNESDAY, ");
        msg.append("THURSDAY, ");
        msg.append("FRIDAY, ");
        msg.append("SATURDAY.");
        throw new IllegalArgumentException(msg.toString());
    }

    this.dayOfWeek = dayOfWeek;
}

While these above examples illustrate argument filters/validators throwing the IllegalArgumentException near the top of the method body, using traps at various locations in source code is also highly recommended.

The goal is to have logic perform a sanity check on the state of objects before relying on them.

Which of the below pseudo code samples looks cleaner?


void methodName() {
    // check all
    sanityCheck1();
    sanityCheck2();
    sanityCheck3();

    // do all
    doSomething1();
    doSomething2();
    doSomething3();
}

void methodName() {
    // check 1
    sanityCheck1();

    // do 1
    doSomething1();

    // check 2
    sanityCheck2();

    // do 2
    doSomething2();

    // check 3
    sanityCheck3();

    // do 3
    doSomething3();
}

The second example is slightly more complex than the first in that it requires the developer to constantly switch attention back and forth from “checking” and “doing”. These examples are trivial and it might be difficult to understand how either could cause a bug but performing all checks in advance lets the developer focus on the task at hand (the core logic) later and also lends well to exporting the validation task to an external class at some later point for performance and code clarity reasons.

Using Descriptive Exceptions

Exceptions are a powerful feature in Java and give developers a chance to gracefully recover/fail in the face of errors. A lot of developers don’t realize however the opportunity for exceptions to automate the process of bug-fixing by simply being descriptive.

I’m a firm believer that computers and people are better at different things and that we should offload the things that we cannot do quickly and accurately or with much interest onto computers. The infinitely mundane task of bug-hunting, in my opinion, should be no different. Bugs ARE there and in order to keep them from occurring twice we need to know their causes, the conditions that got us in this situation. This is something most computers don’t do so well and need somebody at the helm to fix things.

But what we’re used to seeing is this…


IllegalArgumentException at line 123

Wouldn’t it be nicer to see…

IllegalArgumentException at line 123
Cannot withdraw the negative amount (-50.00) from (My Savings) account.
Amount must be 1.00 or higher and must not exceed the amount saved in the account.

This more descriptive exception tells the programmer not only what went wrong but what the method contract expects and even gives an example of how to do the right thing.

If the method was simply passed a value from the user then we know that input validation is the solution. If, on the other hand, a different method called this withdrawal method then we know that it was programmer error that is the cause. And we figured this all out without having to scour the code. The stack trace tells us who the caller is.

MPowerPlayer

The MPowerPlayer is a MIDP 2.0 compliant multi-platform Java-based emulator. What distinguishes it from the rest, and why I recommend it, is its ability to print the line number of offending code the same as J2SE VMs. All other emulators I have tried only show byte offset numbers which are not useful but are unfortunately the norm in J2ME. As I develop MIDlets from a Mac there aren’t many emulators to choose from and I have come to depend on MPowerPlayer and can vouch for its quality.

What might throw one off at first is that this emulator does not have a graphical window pane for outputting messages/exceptions and instead relies on the console for its output. That output looks like this…

j2me-debug-exception.gif

Debugging on Devices

Lastly I’d like to discuss the issue of debugging with devices. Sometimes a bug can only be reproduced within the environment of a mobile device and this is usually the case with errors regarding networks, storage, and threading. In these cases we need a means to output the exception and/or some information about the environment prior to failure.

In the past I have written custom canvas classes to break up large Strings into smaller ones that could be output with the drawString() method. I have also heard others uploading the exception information in a HTTP request to their servers and even some people saving the data to external storage (SD cards).

The take away is that there are many ways to collect this data and the point about being descriptive really pays off (literally if your carrier charges you for data downloads).

With this information I wish you happy debugging!

Entry Filed under: testing. .


Recent Posts

a

Feeds

Blogroll