similar to the ones shown here to help
mitigate the “abstraction penalty” you
might otherwise end up having to pay
in a well-designed object-oriented
codebase.
Bringing Together Two Worlds
Of course, the creation of an environment that allows developers to build
browser-based applications in Java
addresses only one part of the development cycle. Like most developers,
we do not produce perfect code, so we
knew we would also have to address the
issues involved in debugging GWT programs.
Upon first hearing about GWT, people often assume you use it in the following way:
Write Java source. 1.
Compile to JavaScript with GWT’s 2.
compiler.
Run and debug the JavaScript in a 3.
browser.
In fact, that is not the way you work
in GWT at all. You spend most of your
time in GWT’s hosted mode, which allows you to run and debug your Java
code in a normal Java debugger (for
example, Eclipse), just as you’re accustomed to doing. Only when the application is written and debugged do
you need actually to compile it into
JavaScript. Thus, everyone’s reflexive
fear of never being able to understand
and debug the compiled JavaScript
proves to be unfounded.
The secret to making hosted mode
an effective debugging environment is
that it does not merely simulate the behavior of a browser while debugging in
Java. Hosted mode directly combines
true Java debugging with a real browser UI and event system. Hosted mode
is conceptually simple, and it executes
in a single JVM (Java Virtual Machine)
process:
Launch an instance of an actual 1.
browser, embedded in-process, that
can be controlled by Java code via JNI
(Java Native Interface). We call this the
hosted browser.
Create a CCL (compiling class 2.
loader) to load the GWT module’s en-try-point classes.
Whenever the CCL is asked to 3.
fetch a class, it checks to see if the class
has JSNI (JavaScript Native Interface)
methods. If not, the class can be used
directly. If native methods are found,
the class gets compiled from source
and the JSNI methods are rewritten.
Run the bytecode of the entry- 4.
point class, which will in turn request
other classes be loaded by the CCL,
which repeats the process from Step 3.
Step 3, rewriting JSNI methods, is
the really neat part here. JSNI is the
way to implement native Java methods
in handwritten JavaScript, as shown in
Box 2.
Thus, the hosted-mode CCL turns
JSNI methods into thunks that redirect
their calls into the hosted browser’s
JavaScript engine, which in turn drives
the real browser DOM.
From the JVM’s point of view, everything described here is pure Java bytecode and can therefore be debugged
normally using a Java debugger. From
the developer’s point of view, he or
she can see the true behavior of a real
browser being driven by the Java source
code without it first having been cross-compiled into pure JavaScript.
Which brings up perhaps the most
exciting point about hosted mode: because it works dynamically with Java
code and does not depend on invoking
the GWT cross-compiler (which can be
slow), hosted mode is really fast. This
means developers get the same kind
of run/tweak/refresh behavior they
enjoy whenever working directly with
JavaScript.
GWT thus manages to combine
the benefits of a traditional optimizing compiler with the quick development turn-around of dynamic languages. Although the compilation
technology may appear complex, it is
actually fairly standard fare for optimizing compilers. The real technical
problems we encountered along the
way revolved around our efforts to
create UI libraries to simultaneously
account for browser-specific quirks
without compromising size or speed.
In other words, we needed to supply
many different implementations of UI
functionality—version A for Firefox,
version B for Safari, and so forth—
without burdening the compiled application with the union of all the variations, thereby forcing each browser
to download at least some amount
of irrelevant code. Our solution is a
unique mechanism we dubbed
deferred binding, which arranges for the
GWT compiler to produce not one out-
put script, but an arbitrary number of
them, each optimized for a particular
set of circumstances.
Each compiled output is a combination of many different implementation
choices, such that each script has exactly (and only) the amount of code it
requires. It’s worth mentioning that in
addition to dealing with browser variations, deferred binding can specialize
compilations along other axes as well.
For example, deferred binding is used
to create per-locale specializations (for
example, why should a French user
have to download strings localized for
English, or vice versa?). In fact, deferred
binding is completely open ended, so
developers can add axes of specialization based on their needs.
This approach does create a large
number of compiled scripts, but we
reasoned it was a welcome trade-off:
you end up spending cheap server disk
space on many optimized scripts, and,
as a result, applications download and
run more quickly, making end users
happier.
In any event, our experience in developing GWT has thoroughly convinced us that there’s no need to give
in to the typical constraints of Web
development. That is, with a bit of
creativity and some dedicated effort,
we now know it is indeed possible to
retain the richness of more familiar
development environments without
compromising the experience application users are ultimately to enjoy.
Related articles
on queue.acm.org
Case Study: Making the Move to AJAX
Jeff Norwalk
http://queue.acm.org/detail.cfm?id=1515744
Coding Smart: People vs. Tools
Don Seeley
http://queue.acm.org/detail.cfm?id=945135
Debugging AJAX in Production
Eric Shrock
http://queue.acm.org/detail.cfm?id=1506423
Bruce Johnson founded Google’s engineering office
in Atlanta, right next door to his alma mater Georgia
Tech, with the goal of producing Google Web Toolkit
and a number of related tools intended to make Web
development more efficient, effective, and a whole lot
more fun.