Thursday, July 16, 2009

Learning to Love Jetpack, Part 1

I've been having a torrid on-again/off-again love affair with Mozilla Jetpack for the past several weeks, and I have to say, it's been a bit exhausting at times. But try as I may to walk away, I keep coming back for more. I guess fools rush in where less impetuous web developers fear to tread.

It should be said up front that Jetpack is quite immature at this point (having been announced only a couple months ago) and there's a new release almost every week. Putting it through its paces feels a bit like driving a concept car. It's fun, it's exciting, it'll amaze your friends. But is it ready for production?

The basic concept is compelling: Make it possible to develop JavaScript-based Firefox extensions that have special security privileges (the ability to do cross-site AJAX, for example) combined with the ability to vulture page objects at load time, a la Greasemonkey. The goal is to let mere mortals write Firefox add-ons without having to get mired in the XPCOM morass. (If you've ever tried to write a Firefox extension, you know what I'm hinting at. If not, you can get a good whiff here.)

What can you do with Jetpack? Right now, not a lot, other than peek and poke the DOM as a page loads. True, the MozLabs crew recently added audio-recording support, and there's a persistence API that doesn't rely on cookies. Plus you can iterate through tabs, put stuff in the status bar, and create toaster popup notifications. (Woo hoo.) But still, not a lot. You can do most of this kind of stuff with Greasemonkey.

That'll all change soon, though, as Jetpack's APIs expose more and more XPCOM internals. Be clear, a year from now, no one will be mentioning Greasemonkey and Jetpack in the same breath.

Even now, though, Greasemonkey and Jetpack are pretty far apart, under the covers. One difference is the runtime scope. Jetpack runs "above" all open tabs. This is quite handy, because it means you can easily enumerate and manipulate all open tabs (I'll provide some source code for this in a later post), something that's all but impossible to do in Greasemonkey.

Another nice thing about Jetpack is that it comes preloaded with jQuery. You don't have to do anything special to access jQuery methods; just start using them.

There's some built-in support (convenience methods) for the Twitter API, which is kind of interesting.

And you get an integrated development environment with Bespin, which is pretty nice. That, combined with instant-on loading of scripts (no need to restart Firefox), makes for a rapid dev/test cycle, greatly reducing Rolaids consumption. I'll lead you through the dev workflow in my next post so you can get an idea of what it's like to develop Jetpack scripts.

There are a couple of issues (one of them quite serious) to be aware of, though. First, you can't install and use a Jetpack script without installing Jetpack. In other words you can't just give a script to a friend and say "Here, install this, it's cool." Instead it's "Go to the Mozilla Labs download page, install this week's alpha build of Jetpack, along with Firebug 1.4, and pray God my script still works on your machine next week."

The MozLabs guys say that eventually, Firefox may come with embedded Jetpack support so that no one need proactively do a Jetpack install before being able to use Jetpack scripts. That would be a Very Good Thing, except for one potentially nasty issue.

The nastiness has to do with the way Jetpack facilitates memory leakage. Simply put, it's extraordinarily easy to write scripts that eventually cause Firefox to hang. One can argue that adhering to best practices will prevent this (which is true), but I think that if the Jetpack agenda truly does revolve around getting mere mortals (people with modest JavaScript skills) to participate en masse in creating Firefox extensions, the potential exists for disaster. You're inevitably going to have large numbers of amateur programmers getting into trouble with memory leakage, and that's not going to do anything good to Firefox's already poor reputation for memory leakage nor to Jetpack's reputation.

As I see it, the problem is really twofold. Fold Number One has to do with the way XPConnect works. (XPConnect is the bridging technology that allows JavaScript to interoperate with XPCOM objects written in C++.) Without going into gory detail, C++ and JavaScript have different memory management models. One is a world of reference counting, the other is a mark-and-sweep world similar to Java. When you wrap a C++ object in such a way that it's usable from JavaScript, you're entering a whole new universe of memleak possibilities. This is the domain where Jetpack lives.

The second aspect of the problem is that the kinds of capabilities that attract programmers to something like Greasemonkey or Jetpack tend to draw on programming patterns that are inherently dangerous from a memleak point of view, chief among them the Observer pattern. Sometimes I think the Observer pattern is actually better termed The Cyclic Reference Memleak pattern, because you're basically creating objects and/or wrappers that maintain references to each other. It's a great way to generate memory leaks.

Again, any competent developer (myself not included) will understand the importance of best practices here, and staying out of trouble is not rocket science. But to expect the average script kiddie to know or care about memleak mitigation is like expecting the average McDonalds customer to know how to make a roux.

In any case, Jetpack is an interesting beast and I continue to be fascinated by (and infatuated with) it -- enough so, that I intend to devote at least a couple more blog posts to it. Check back here in a day or two. We'll have some fun.

Friday, July 10, 2009

JavaScript Expression Closures and Why They Rock

JavaScript expression closures (new for JS 1.7 but syntactically even cleaner in 1.8) are one of those things that seem very so-what the first time you hear about it, but leaves you slapping your forehead and saying "OMG this is so darn freakin' cool" repeatedly after you start using it. Why? Because OMG. It's so darn freakin' cool.

The basic notion is that instead of writing short utility functions (which I have a million of) as, for example
function square( x ) {
return x * x;
}
you just write
function square( x ) x * x
which (yes yes, I know) looks very so-what, but bear with me for a moment. The short syntax starts to become more compelling when you begin using it in anonymous functions, particularly callback functions (which, as you know, tend to be anonymous a great deal of the time). For example, suppose you have a custom comparator for the sort() method of Array:

function descending( a,b) {
return b > a;
}

[5,1,3,2,4].sort(descending); // [5,4,3,2,1]

You can instead write it as:
[5,1,3,2,4].sort( function(a,b) b > a );
Another fairly trivial example: Suppose you want a function that will constrain strings to a certain length. You can do something like:
function limit(s, n) s.length > n ? s.substring(0,n): s
As a more elaborate example, suppose you have the following code, designed to convert a "camelCase" string to underscore_format.
function underscore( str ) {

function toUnderscore( s ) {
return '_' + s.toLowerCase();
}

return str.replace(/[A-Z]/g, toUnderscore );
}

// underscore( "aName") --> "a_name"

With the new closure syntax, you can do:
function underscore( str )
str.replace( /[A-Z]/g,
function(s) '_' + s.toLowerCase() );
Here I've converted not only the outer function, but also the callback to replace(), to expression-closure form. (I split it into 3 lines for readability, but it will still execute correctly as a 3-liner. You don't have to write these things as one-liners.)

Still not convinced? Try using this syntax (supported in Firefox 3+, and anywhere else JS 1.7 or 1.8 are implemented) in some functions yourself, and see if your code doesn't become easier to write, shorter, and (in most cases) more readable. It may be only a small improvement on the more verbose older syntax, but an improvement is an improvement. I'll take it.

Thursday, July 09, 2009

Why Google Chrome OS is a nonstarter

As the entire world knows by now, Google recently announced its intention to muscle its way into the operating-system space (supposedly) by way of something called Google Chrome Operating System.

But is it really an operating system? By Google's own account, it's actually an instant-on windowing system sitting atop a Linux kernel, and it will run on certain netbooks only, using certain chipsets only. Google is reportedly working with Acer, Adobe, ASUS, Freescale, Hewlett-Packard, Lenovo, Qualcomm, Texas Instruments, and Toshiba to "deliver an extraordinary end user experience." I take it that means Flash will be supported, since Adobe is on the partner list.

But where are the value-adds in this picture? What, exactly, does Chrome OS bring to the table that you can't already get elsewhere?

Not much, it turns out.

"Speed, simplicity and security are the key aspects of Google Chrome OS," acccording to Google. Speed, in this case, means instant-on. Turn your netbook on, it lights up, you have e-mail and browsing. Of course, you might have to wait a few seconds while the netbook (re)acquires a wi-fi connection, but at least you don't sit there for two minutes waiting for Godot.

This sounds like a great technological advance until you realize that the same instant-on capabilities promised by Chrome OS are already available via HyperSpace from BIOS vendor Phoenix Technologies Ltd., Splashtop from DeviceVM Inc. and Cloud from Good OS, as well as (more recently) Presto from Xandros Inc. In addition, Dell is putting special instant-on features in its Latitude laptops, and oh by the way, I can put my last-year's-model Dell laptop to sleep any time I want and wake it up later in the day, right now.

Bottom line, instant-on is not new, and it'll be even less new when netbooks running Google Chrome OS become available for consumers in the second half of 2010 (according to Google).

Simplicity is another supposed value-add. What this really seems to mean is that you can only run web apps, and you have only one UI to learn (Chrome's). Which is fine. I spend most of my day in a browser already, thank you.

Security is the third main value add, according to Google. Security expert Bruce Schneier has already derided this claim, however, calling it "idiotic." Far be it for me to disagree with such a distinguished expert.

What are we left with? In terms of new technology, not much, really. There's nothing here you can't already get elsewhere. The only hope Google has of differentiating itself in this market is to offer a jaw-dropping user experience, something so compelling that nothing else even compares. In other words, they have to out-Apple Apple. I have yet to see Google do that -- with anything. Maybe this time they'll pull off a miracle. But somehow I doubt it.

Tuesday, July 07, 2009

An exercise in riddle-solving

1 2 3 4 5 = 1
5 4 3 2 1 = 2
1 1 1 1 1 = 5
2 2 2 2 2 = 1
3 3 3 3 3 = 6
4 4 4 4 4 = 2
5 5 5 5 5 = 7
6 6 6 6 6 = 3
1 1 2 2 2 = 6
3 3 4 4 4 = 7
1 1 1 1 2 = 1
1 1 1 1 3 = 6
1 1 1 1 4 = 2
1 1 1 1 5 = 7
2 2 2 2 6 = 3
2 2 2 2 5 = 7
2 2 2 2 4 = 2
2 2 2 2 3 = 6
2 2 2 2 2 = 1
6 1 1 1 1 = 2
5 1 1 1 1 = 8
4 1 1 1 1 = 5
3 1 1 1 1 = 2
2 1 1 1 1 = 8

3 1 4 1 5 = ?


This puzzle comes by way of a terrific blog post by James Marcus Bach, who in turn got the puzzle from Trey Klein. Bach candidly reports: "I found it difficult to solve. Took me a couple of hours."

As a rule, I hate puzzles of the recreational (purposeless, do-nothing) sort -- colloquially known as brain-teasers -- simply because they accomplish nothing except to waste time and make me feel stupid. I either already know "the trick," or when I find out what the trick is, it turns out not to be useful for anything other than solving the puzzle in question. Then I feel cheated and stupid.

But I'm inherently a masochist, so naturally, when I saw the above puzzle, I just had to try it. ;)

I resolved not to spend more than two or three minutes on it, though.

It turns out, I got the puzzle right, and it took me only a minute or so. You might want to stare at the numbers yourself for a couple minutes now, before reading the next paragraph.

The supposed "answer" and its reasoning (involving a somewhat painful-looking formula with modulo arithmetic) is given here. I took a far more pragmatic approach. I looked only at occurrences of "5 =" and saw that in 3 out of 4 cases, a 7 appeared on the right-hand side of the equals sign. If this is some kind of casino game and I'm betting real money, and I see "5 =" come up again, I'm betting on 7 being the answer.

I decided to reverse every line of the problem and try it again. I looked at each occurrence of "7 =". And again, 3 out of 4 times, "7 =" ends up paired with 5.

That's it, I decided. The answer must be 7.

It turns out 7 is the correct answer.

"But you just guessed!" someone will say. "You didn't prove that the answer is 7."

My retort is that neither did the person who wrote the explanation given here prove that the inevitable answer is 7, because he or she didn't prove that the given explanation is the only explanation that will work; he merely gave an explanation that is consistent with 7 being the answer.

I'm 100% sure if I had 3 hours, I could come up with at least a couple of formulas that, given the input data shown above, will be consistent with an answer of 7. I can also come up with a couple of formulas that are consistent with an answer of 1. So which formula (out of these several formulae) is "correct"? Is any one formula provably the only possible correct one? That's the question. I'd argue it's not even possible to know if that question can be answered.

Still, is it reasonable to attack a problem like this heuristically, and "bet" on an answer that seems (statistically) likely to be correct? Is it better to spend 3 hours arriving at a formula that's consistent with a given answer (but that could be "shot down" by a different formula later)? What kind of approach do you take if you're in an out-of-control spacecraft and you need an answer within 3 minutes or you'll burn up on re-entry? What if you're in the Titanic and have a full 24 hours' notice of icebergs ahead and need to decide on the correct heading to take? Do you "bet the farm" on a heuristic method -- or on a formula that seems right (and has the appearance of being rigorous, because it's so formulaic) but isn't provably correct?

I think the approach you take depends on the situation, but it also depends on your personal working style. In the absence of a reason not to, I tend to take a heuristic approach. My style is not to waste time, even when I have time to waste. What's yours?

Wednesday, July 01, 2009

Taking microURLs to the next level

If you've been following my Tweets lately, you may have noticed that I've begun using 3.ly ("threely") as my URL-shortener of choice. Before that, it was bit.ly, and before bit.ly I used TinyURL.

Like many Twitter users, I moved from TinyURL to bit.ly for the simple reason that bit.ly produces tinier URLs. Threely gives even smaller URLs. But that's not why I'm moving from bit.ly to 3.ly.

Threely has an ambitious goal: to take micro-URL rewriting to the next level. The Threely folks haven't yet said what their list of services will include. But already, they offer an interesting glimpse of what they might be up to. All you have to do is append a hyphen to any 3.ly URL in order to activate a hit counter. If you surf to the hyphenated URL, you come to a preview page that displays the hit count and one or more continuation links. (To see what I mean, try http://3.ly/ymZ-, which links to one of my previous blog posts but first takes you to the hit-counter page.)

One can imagine a range of services that Threely could offer based on short query strings. For example, what if, by appending "-1" to a 3.ly URL, you could have Threely not only track hit-counts but send you a daily or weekly report of traffic on that URL via e-mail. Suppose "-2" means the same thing, except your e-mail contains verbose results instead of cursory results. The verbose results might include the HTTP headers from each visitor's GET request, the date/time of each request, etc.

There isn't a Threely API yet, but one can imagine that Threely's API could offer various takes on "URL-rewriting-as-a-service" (URaaS? oh dear God please not another acronym...). Or should we just call it micro-analytics?

As I say, exactly what the Threely folks have in mind, I don't know. But I'll be watching their home page closely, and signing up as a registered user as soon as they make sign-ups available. I have a feeling this could get interesting.