2010-10-04

Lessons learned porting from jQuery to Closure

When I realized the next major feature leap for the Oplop project was going
to require adding drag-and-drop to the Chrome extension
(to become a web app once Google's web app store launches), I realized that my
use of jQuery would not be enough to ease the development of complex UI
interactions. That meant
either integrating jQuery UI into Oplop or switching to another JavaScript
library such as Google Closure or YUI.

In the end I chose to go with switching to Google Closure. I had two reasons
for this.
First, all of my serious JavaScript work has involved using jQuery, so I was
curious to use a different approach to JavaScript (even though I have enjoyed
teh functional approach jQuery promotes). Two, with me starting work for Google
come early/mid 2011 I figured I should learn the JavaScript library my future
employer uses so I can possibly use my 20% time to contribute to
JavaScript-based projects.

It ended up taking me three days, but the work is done and has landed in
Oplop's code repository.
Along the way I learned a few things that might useful to others who decide to
take the plunge and learn how to use Closure.

Jumping around in the docs

First thing I learned is that the Closure Library API has a slight
disconnect between types and functions. If you look under the Type Index tab
of the API docs you get a list of all the types in a certain namespace. That's
fine, but to get a list of functions in a namespace that are not tied to a
type, you need to look under File Index. That's a counter-intuitive naming
scheme. And after having used Python's documentation for so long, I come to
expect to have both types and functions defined in the same namespace to be
listed in the same location. I mean if some types and some functions are
connected enough to be in the same namespace, why not list them in the same
place? This was an annoyance for me.

Use all of the tools

Closure is more than the Closure Library. There is also the Closure
Linter
which makes sure that you follow a JavaScript style guide. There is
also the Closure Compiler which not only minifies your code greatly, but
will also perform sanity checks on your code. And I didn't even use Closure
Templates
.

All of these tools somewhat feed into each other. For instance, the Closure
Linter makes sure that you have JSDoc type annotations. The
Closure Library lets you specify namespaces and what symbols should be exported
outside of the JavaScript code, e.g., what is called directly in your HTML. All
of this is used by the Closure Compiler to do type checking, proper
minification without bad symbol renaming, etc. By supporting one tool you end
up gaining benefits from the other tools, leading to one potentially caring
enough to use all of them and maximize their benefits.

I used all the tools for Oplop and I am glad I did. I caught a couple bad bits
of JavaScript code early on (where I couldn't do automated tests as testing
Chrome extensions is still a rather manual process). I have proper
documentation for everything. I even have JavaScript code that is
consistently formatted which makes it easier to read. I even got the
side-benefit of getting to minify the code easily which led to shaving 14K off
the zip file for the web app.

Supporting all of these aspects of Closure turned
out to be worth it. Yes it adds a compilation step to my JavaScript work, but
that is acceptable to me as JavaScript's leniency towards potential errors
makes type checking and such a useful thing (if automated testing of Chrome
extensions was easier I may be singing a different tune right now, but that
might be for another time where I try to tie Selenium or something into Chrome
page actions or something).

You are either in or you're out

Closure is an ecosystem. It is not like jQuery where you just use it
here and there to make accessing or manipulating the DOM easier. If you want to
truly use Closure, you have to make a commitment to truly use it. This comes
with some consequences.

Probably the biggest consequence is that if you use other third-party
JavaScript libraries you need to add support for them to work with the various
Closure Tools. You can obviously skip doing this, but then you either have to
start special-casing third-party code (e.g., not running the Closure Linter
over it) or you lose certain benefits (e.g., the Closure Compiler not being
able to detect all possible type errors). So to truly gain all benefits you
might want to retrofit third-party code with at least JSDoc markup (you can do
this externally using extern files). Some of
Google's APIs have extern files already created
along with jQuery 1.3.

Using more raw JavaScript

But probably the biggest shock out of all of this was having to shift to using
raw DOM objects. When one gets used to doing

$('#node').css('background-color', 'red');

it ends up feeling odd doing

var node = goog.dom.getElement('node');
node.style.backgroundColor = 'red';

The niceties that jQuery wraps DOM nodes do spoil you.

But there is obviously a performance penalty. Something to keep in mind with
Closure is that this is the code that Google uses, the company obsessed with
performance. If there is a way to expose a function that does something quickly
that is a pattern not easily exposed through the DOM consistently, then there
will be a function for it. But for something as consistent as changing CSS
values, then there is no such added support.

Initial verdict

So was it worth three days of coding to switch? Having not started the coding
yet for the fancy things I want to add to Oplop that drove me to even
considering switching, it's too early to give a definitive answer. But what I
can say is that I am not sitting here regretting anything. I feel like my
JavaScript is in better shape than it was thanks to Closure forcing me to
follow better coding practices. And the benefits from the compiler thanks to
following those coding practices also make me feel better that my code is in
reasonable shape.