Thursday, June 5, 2008

How I lost 3 hours of my life to dynamic typing

Today, while working on integrating Chronoscope into Google's GViz API, I ran across a bizarre problem, the depths of the problem would flush 3 hours of work time down the toilet.

In order to integrate Chronoscope with GViz, I decided to provide some lightweight GWT 1.5 overlays on top of the API. To use the API, it is recommended to use the Google AJAX Loader. Quickly reading the docs, it seemed very straightforward. You start out by


<script src="http://www.google.com/jsapi?callback=handler">

After the google.load API is available, you write

function handler() {
google.load("visualization", "1", function() { alert("visualization api loaded!"); })
}

or do you?

Here comes the pain


So, if you're already familiar with the AJAX Loader API, you'll recognize I made a typo. Between the time I read the documentation, and the time I wrote the code above, the types of the parameters needed for this call morphed in my head. The third parameter can include a callback for asynchronous loading, however, the callback isn't passed as a function, but as a object, like this

google.load("visualization", "1", { callback: function() { alert("visualization api loaded!") } });

and I would have discovered this problem 3 hours earlier if it hadn't been for one fact: the wrong code locks up Firebug and generates an infinite "Loading..." in the browser tab.

If you run the wrong code inside a regular HTML page, it won't have this effect. But I was running this through an Apache Shindig IFRAME, which had loaded script containing this code via _IG_GetCachedURL, and somehow the combination of the IFRAME, the proxy loading of the script, and the cross-domain included JSAPI combined to kill Firefox. I couldn't use Firebug to set breakpoints, to inspect the network to see what stage of loading caused the failure, to see which script might be the culprit, or even to inspect the HTML DOM. I tried FF3 and installing Firebug 1.2beta, no dice. I tried Safari debugging, no dice.

Eventually, I came back to read the docs two or more times again, and discovered how I had screwed up the type of the third argument. In many other AJAX libraries, like Dojo or jQuery, they are more forgiving, and probably would have checked if the third argument was typeof(o) == "function" or "object" and acted accordingly.

I know, you're saying "Serves you right! You should RTFM more carefully!" Unfortunately, these kinds of errors are bound to be made by mere mortals, even if they do RTFM, especially with the size and complexity of todays AJAX apis.

Why do I endure using Java by using GWT my Javascript Ninja Brethren? When a simple mistake, or typo can waste half your day, you'll understand. And now that I've written a strongly typed GWT GViz/AJAX Loader wrapper, it's unlikely any GWT user will ever have to suffer the same fate.

-Ray

No comments: