Friday, August 21, 2009

The Bug from Hell

Executive Summary

One full week lost. Zero output units. It was the bug from hell. If you have any faith in your software schedules, read on.

I am writing a SketchUp Ruby. Stuff that worked Friday stopped working Saturday morning. I got to the bottom of the problem Thursday morning. In a lifetime of coding I've never been stopped for five days by one bug. It was subtle.

The trickiest bit about Rubies is that your UI runs in a browser. That means that the Ruby code that manipulates the model has to communicate with the JavaScript in the browser. (Note: this is another case where you have two languages to use and zero choices about which you use.)

JavaScript on the Front Line:

The general idea is that since the user is in charge, JavaScript notes what buttons are clicked or whatever. JS can then call a Ruby function that will dig up whatever data is needed or manipulate the model in the manner requested. If it needs to send data, Ruby prepares a bit of JavaScript, like this:


script = 'name_of_javascript_function( whatever, facts, are, required )'


Ruby hands this script to a webdialog object (prepared by the web dialog and passed to the Ruby callback). The webdialog executes the script, presumably calling JS functions that make use of the data. The whole communication thing is at best inelegant. This is NOT pythonic.

"No, no, Monty! I didn't mean you. You are totally pythonic."

Monty, my pet python, has been crabby since I turned him into a vegetarian. Sorry for the interruption.

Ruby in the Trenches

Saturday morning I moved the JavaScript out of the HTML file and into a separate JavaScript file so I could validate the HTML. I've got validated HTML, but the code no longer worked. It seems that JavaScript correctly calls Ruby. Ruby correctly gathers the data wanted and correctly forms the script needed. But Ruby is definitely not succeeding in getting back to JavaScript. The final step, executing the JavaScript script, is not happening. At one point the JavaScript function that I wanted called by the script was reduced to launching an alert box that said, "Hooray! Finally!". It never said "Hooray! Finally!".

Note that the tool set is completely primitive. There is no NetBeans, no Eclipse, no debugger. On Windows, we can choose any browser we like, provided we choose MSIE. At one point it reported that I had an error in my JavaScript at line 51 million and something. Ugh. The tiniest little bit of error checking and it's too buggy to be helpful.

For debugging, you stick print statements into the Ruby and pop up alert boxes in JavaScript. Before Saturday ended I knew that my JS was correctly calling Ruby, that Ruby was preparing a valid script passing correct data and was calling the correct method of the webdialog (the webdialog that JS had passed to Ruby). And that was the end of the road.

Swapping Code

By Tuesday I knew that the same code that worked also failed. I started with a successful, small test package and the unsuccessful, larger actual package. I began removing parts of the larger package deleting bits one a a time until I could find the guilty party. I ended with a still-failing package no larger than the test package.

Wednesday found me copying Ruby source functions from the test to the failing routine. Still fails. Copy from the failing to the test? Still succeeds. So repeat this with the JavaScript functions. Same result.

Early Thursday I am convinced that it is a timing issue. How else could two copies of the exact same code fail and succeed?

"Martin, what are you talking about? It's single-user, single-threaded code! Timing issue?"

"OK, Monty. You explain it."

That got me back to Saturday morning. I had taken the JavaScript out of the HTML, where it had been at the end of the body of the page, and put it into a JavaScript file. I linked to the JavaScript file from the <head> section of the HTML, a common practice that I will never again practice.

Moving the "load the JavaScript file" command from the <head> of the HTML to the end of the <body> of the HTML turned the failing code to successful code. Bug in the SketchUp linkage: if your HTML is not completely processed, the webdialog that it passes to Ruby cannot execute the JavaScript script.

Moral?

(In Ruby convention, getters for booleans are suffixed with a "?". This section should return a boolean.) Moral? Maybe.

I let my ego get in the way. Hot shot programmers fix their own bugs, right? Instead of punching ahead on my own, I should have recruited an associate. Wise old programmers get help when they need it. I'll try to remember that.

1 comment:

  1. JavaScript and Ruby == Nightmare on Sketchup St.!

    This whole game of "footsie" between Java and Ruby is worse than giggling jr high school girls passing "Do you like me? Yes or No" notes under their desks and leads to these unessesary nightmares of which you speak.

    Sketchup needs a "real" GUI UI and not some hap-hazard-ly thrown together unholy matrimony of pubescent "parcel passing" programming putrification! We need Python!

    ReplyDelete