Tuesday, December 8, 2009

GWT 2.0 was released today, and even though I've been using it for months and contributing to it, I didn't realize the significance of this release until I saw the Google Campfire event, because I've been exposed to each new feature incrementally, rather than all at once. If you take a step back, look at what has been accomplished since 1.7:

Development Mode

Who else but Google could build a plugin that runs on 3 different browsers on 3 different operating systems, deeply integrated with the Javascript VMs on IE, WebKit, and Firefox, that runs Java in a hybrid mode, where Java code runs in any JVM, and Javascript code is injected and ran in the browser as Javascript over a network connection? Do not underestimate the difficulty of doing this, especially when considering that Javascript can hold references to Java and vice-versa, causing problems for accurate garbage collection. Development Mode is an amazing productivity tool, made possible by some really awesome technology under the hood. Let's get a w00t! for the engineering that went into this.

UI Binder

Following the GWT mantra "Why do at runtime what you can do at compile time?" UIBinder is an extensible declarative language for constructing user interfaces, injecting those constructs into your Java code, and optimizing and bundling resources like stylesheets, images, and localized text. While it may seem like a throwback to use XML/XHTML in an era when HTML5 tagsoup and JSON are emerging as favorites, you have to consider what has been bought in exchange. UiBinder constructs HTML at compile time, which means it minimizes the number of DOM operations needed to get your UI up and running. It treats stylesheets as an intelligence resource, obfuscating and compressing them just as the GWT compiler does for JS, as well as providing local scope for CSS classes so that you can compose stylesheets written by different parties together without worrying about conflicts.

Google Eclipse Plugin

Technically, it's separate from GWT, but I'll list it here because of its tight integration with GWT. It provides intelligent integration between your Java source, JSNI methods, and UiBinder files. Again, this product alone would be a major event unto itself, but it's almost under-the-radar in Google's Campfire event.

Code Splitting

The value that whole-program compilation for JS brings to the table is no better demonstrated than it is here, by the ability of the GWT compiler to statically compute transitive callgraphs and dependencies from any callsite you desire, and split off that chunk of code for deferred loading. Ask yourself, if I handed you a hand-written large JS application like Maps, or GMail, or Y! Mail, how long would it take you to fully modularize all of the libraries used, get all of the dependencies exactly right (if you need feature F, load library F, but F needs G and H, so load libraries G and H). You can point to popular JS libraries using complex JS module loaders with dependency management, but keep in mind, that is all done by hand, on very mature libraries. GWT Code Splitting brings this functionality to mere mortals in just a few lines of code.

Constraint-Based Layout

Many modern JS libraries have punted on making CSS work for general compose-able widgets, and rely on JS to perform layout calculations for widgets. This works well, but has the downside of laggy performance, as the browser rendering engines are optimized for layout calculations, and often performing JS layout can cause excessive browser layouts. You'll see this in split panels or scroll panes sometimes as the divider or scrollbar lagging the mouse position. Joel Webber of the GWT team has finally cracked the code to make CSS based layouts work in a predictable fashion, and as a result, you can now compose arbitrary layouts in GWT with predictability, a productivity enhancement unto itself, even if some flexibility is lost, end-user performance and development speed are gained.

ClientBundle

Few people realize that GWT has been doing automated image sprites for a long time. ImageBundle, introduced in GWT 1.4, allowed GWT users to simply refer to images on disk, and the compiler would pack all of those images into a single file, transforming references to the images automatically into sprites. Then with 1.5/1.6, FooBundle, or ImmutableResourceBundle was introduced to the GWT Incubator. FooBundle/IRB took spriting to the next level by allowing all of your resources to be bundled into one or more files, or even inlined in your compiled JS as a gigantic data URI. GWT 2.0 introduces IRB into the core SDK, now called ClientBundle, it has been enhanced and polished. Simply put, ClientBundle allows GWT developers to reduce the number of HTTP requests for resources to just 1 or 2 which are cached forever, pack images optimally, optimize and minify CSS, and much more. Did you know that ClientBundle works with internationalization? That GWT ClientBundle can automatically flip images for Right-To-Left locales like Arabic, and flip CSS rules as well? Crazy awesome!

Optimized for Compression

I'm some what tooting my own horn on this feature, since I contributed it, but GWT 2.0 produces obfuscated Javascript in a way that no other tool on the planet does. In addition to renaming pretty much every variable in your entire program in a few symbols as possible, it actually re-orders code to increase gzip compression ratios. And that's just the beginning. The ability to just keep plugging in optimizations to this toolset is unbounded. Automated PNG optimization in the future? Check. New Deflate algorithms? Check. The list goes on.

HtmlUnit for Testability

You want testing? GWT's got you covered. Java tests? Check. Selenium tests? Check. Web-Mode test in real browser? Yep. But what's really new, is that GWT can run tests in a simulated browser environment thanks to HtmlUnit. This has two immediate benefits: 1) You can run your tests anywhere and not have to worry about prepping a test environment or platform specific details and 2) Tests can startup much quicker because they don't need to use a real browser. Again, it would seem like an almost irrelevent footprint if it weren't for the fact that a lot of effort is going into making this work correctly.

But wait, there's more! These are just the main bullet points, there's lots of other changes under the hood that are also important, let's look at a few:

Story of Your Compile, Compile Reports

Think of it as Compile-Time SpeedTracer. SOYC gives you lots of detail about what each part of your app is contributing to the output in terms of size, and what the interdependencies are. This provides valuable feedback as to where to look to reduce bloat, or split-off code better. This would be the equivalent of a JS tool that looked at your jQuery application, and told you exactly how many bytes were used by each method in each jQuery plugin you're using, and which modules and functions pulled in the others. Think about it.

Better stack traces, and stack trace emulation for IE6

The GWT team simply isn't content with the status quo. When it doesn't exist, invent it. Internet Explorer does not provide proper Javascript stack frame traces. This means when something goes wrong in your application, it can be difficult to get a detailed report about what call sequence triggered it. GWT 2.0 contains the ability to switch on stack-trace emulation, which causes the compiler to insert line number, file, and callstack recording into every program method. When an error occurs in a GWT application compiled for IE6, you can actually reverse obfuscated emulated stack trace output back into real Java stack traces that tell you file and line number. Com'on, you're not excited yet?

Schedule Finally

Javascript is an event driven programming language. When the Javascript interpreter runs, it is the context of an event pumped through an event queue that enters the interpreter/VM through some handler callback, or default entry point. GWT 2.0 recognizes this fact by becoming the gatekeeper to every entry/exit of the application code, and by doing this, it can perform quite a few useful things. One is, it can implement the idea of an uncaught exception handler and enforce it, so that any exception that causes the JS interpreter to exit/yield can be diverted to a custom handler of your choice. More importantly, GWT can take control of how code is scheduled for execution, beyond setTimeout()/setInterval(). GWT 2.0 introduces the concept of Schedule Finally? What is it? Simply this: Defer execution of a piece of code to run after all other code in the current execution context is run, but before the next event is pumped. This is used, for example, by the GWT style injector, so that CSS style injection can be deferred to after the current event is handled, but run before the next is. This can allow efficient batching of operations that mutate the DOM, among other things.

I could go on, tons of compiler optimizations, Directly Evalable RPC, Conditional Deferred Binding Properties, HTML Standards Mode Support. One could make the argument, that almost everything in this list can be done, or has been done, elsewhere, or in parts of other tools. But that's why GWT is so beneficial. It unifies where other approaches fragment. Sure, you could combine your own code splitting, with your own handrolled JS loader, with someone else's image sprite tool, with another guy's test framework, and someone else's minifier, and this guy's trace analyzer, and that guy's widget toolset. And if you think you could achieve the same outcome, you'd be absolutely right.

GWT isn't about doing what isn't possible elsewhere. It's about making you productive doing it. It isn't about extolling the beauties of Java, it's about pragmatically recognizing the leverage you get from the existing toolchain, IDEs, test harnesses, and types. It isn't about hiding the DOM, CSS, and the browser from you. It's about allowing you to write your abstractions yourself more productively, just like you'd do in hand-coded JS anyway. Someday, there may even be the ability for GWT to compile other languages to Java, or even process JS with type annotations.

GWT makes productive, large scale web development possible, and enables next-gen applications to be built reliably.

Methods on the same class with identical names can be exported as a single Javascript method using run-time type-detection and dispatch. You pay a price in the form of a dispatch table encoded as a JSON object, but only for methods with overloads.

ExporterUtil::exportAll()

Feeling lazy? exportAll() will export every single exportable type in your classpath so that you don't have to invoke GWT.create() manually.

ExporterUtil::exportAllAsync()

All exports compiled to a separate JS fragment, loaded asynchronously, and invokes window.onexport() when done.

Exporter.export() deprecrated

Now simply invoking GWT.create(SomeClass.class) is sufficient for export.

Supports GWT 2.0 $entry function

$entry preserves Java exception handler behavior as well as the correct event-loop entry/exit, like running scheduleFinally commands on exit.

Requires GWT 2.0 RC2 or higher

Because $entry and code-splitting are now integrated features.

Structural Typing

I'm also about 90% done implementing Structural Types for exports, which allows idiomatic interoperability between JS and exported APIs. Structural Typing will be available in an upcoming 2.10 release real soon now.

The future

GWT Exporter was originally written for some dire needs I had, and the codebase is now over 2 years old. The latest additions have been difficult, as the codebase is getting messier. The 2.10 release will be the last release, afterwards, I will use the knowledge gained from the library to work on a rewrite for GWT core that may or may not make it into a future SDK distribution.

The goals for the future releases will be (1) Never pay for what you don't use, that is, exports should only bloat code if they absolutely must. 2) Provide flexible way to customize output for various idiomatic Javascript styles. You should be able to generate APIs that look like they were designed by hand. 3) Look at ways to process JSDocs and provide additional ways to automatically bridge JS and Java objects. 4) Improve error checking, diagnostic messages, and quality of auto generated JS docs.