Google Health started to pick up speed around the time I first joined Google. A few of us had whipped up a prototype in our 20% time. GWT naturally came into the picture as we tried to decide what we would use to build our client infrastructure: hand-written JavaScript with other internal JS libraries, or GWT. We didn't jump right to GWT until we did our homework. We loved the concept, but GWT was fairly new back then. We were cautious about whether it was mature enough for a production-planned project like Google Health.
Since many of you are faced with these same decisions, I thought it might be useful to share a synopsis of that first email thread I wrote to the GWT team titled "GWT, to use or not to use". In it I included a link to our mock as well as 4 key questions:
Scott Blum from the GWT team responded that "in general anything you can do in HTML, you can do with GWT". Joel Webber, one of the founders of GWT, added "Looking at the your mocks... it appears as though you would want to fetch lots of information from the server during the course of interaction with the user, and to update both the form on the left and the results on the right interactively. I think GWT would be an excellent way to do this". To get a better feel for what GWT development meant, I created a sample project to test the waters. After exploring the widget library, I was able to build a functional prototype quickly. I tried a bunch of different widgets and found that they are easy to use and extend. The RPC calls were straightforward as well, and tied into the Servlet framework nicely. I was very pleased with the result of the prototyping.
Scott also confirmed browser support for "Recent versions of Opera, Safari, and Mozilla/Firefox; IE6+", which was satisfactory for us.
At the time, the i18n support was still in the works, but we were assured that it would arrive very soon. We were a little bit worried about how hard it would be but we were pleasantly surprised to learn that the implementation was really simple. All we had to do is to inherit the i18n package, create the constant and message classes along with their associated property files for all the strings, messages that need to be externalized.
The initial answer I got regarding our fourth question was "your entire application is monolithically compiled into aggressively optimized and obfuscated JavaScript. It's a "pay-as-you-go" model, code you don't call gets pruned", and "GWT uses a trick to allow its script to be reliably compressed, resulting in a 3-5 fold decrease in size". I had vivid memory of working on scripts to prune and obfuscate handwritten JavaScript code in my previous job, and how it required constant tweaks and tune-ups. As painful as it may be, performance tuning is a very important step for any large-scale JavaScript application. The initial download time and execution speed are crucial and greatly affect the user's perception of an application. As a skeptical engineer, I performed my own tests to validate these claims and test performance, initially and prior to launch, to make sure that the code was pruned, optimized and obfuscated. The results of this testing proved to me that GWT could live up to our expectations.
Finally, after receiving convincing arguments and techniques for creating a custom-cut Google Data library, the choice for which technology to use to bring Google Health to production was obvious, and the rest is history. My sample GWT project became the launch pad for the Google Health client infrastructure.
Of course we didn't develop the whole application without running into technical challenges. We grew our application as GWT itself was still growing up. There were times when we realized that some of the little details in JavaScript were not exposed through GWT. In most of these cases, we used JSNI to access lower level JavaScript functionality. At one point, we also noticed that as we continued to build the application the initial download time started growing as well. We analyzed all the requests and realized that there was cumulative latency introduced by each little icon, logo and other images that needed to be requested and loaded during the application loading. We used GWT image bundle to handle all the images and it considerably improved performance. Finally, in cases where we thought a certain widget should be further extended, we took one of a few approaches: first we checked for such a widget in the GWT pipeline; second we checked the developer forum to see if someone has already constructed what we need and contributed it back the open source community; third, we developed our own and contribute it back to GWT for potential inclusion in a future release.
Looking back today at a successful Google Health pilot and public launch after 2 major UI redesigns, numerous UI experiments including proof of concepts and user studies, it's hard for me to imagine accomplishing so much in last two years without GWT. We were able to do all the fancy JavaScript stuff in half of the effort it would have taken with handwritten JavaScript. We were able to write truly object-oriented UI code, refactoring and reuse were much easier, and leveraging IDEs like IntelliJ or Eclipse made UI redesigns much easier to absorb. GWT's compile-time elimination of dead code also meant we didn't have to worry about unused code that was still hanging around the codebase (of course it's best to do code cleanups every now and then), and we were also able to easily create unit tests for our UI code with GWT's integration with JUnit, which saved us lots of debugging time as our engineering team grew. It's been an amazing experience.
The next and hopefully last release candidate for GWT 1.5 is almost upon us. In anticipation, we'd like to really crank up the excitement level and, well, the sheer geek factor of this here blog.
If you are new to GWT, you may be wondering what all the excitement is about. Why is GWT different from other framework-style solutions? GWT is more of a tool chain and a baseline technology rather than a particular application framework. So, although GWT has lots of libraries, you can use as many or as few as you find useful. Don't like GWT's UI? You can build your own using the DOM classes. Want to use JSON instead of RPC? It's easy. In fact, it is completely possible to start from scratch and build your own framework using GWT and benefit just as much from GWT's overall approach to debugging and compilation.
So, high-level, why should you consider using GWT for your next big web app?
We doubt you are someone who is easily influenced by mere assertions or marketing pitches, so we've put together the next few blog posts to take a look at exactly how GWT achieves these performance gains, and how it makes working with JavaScript easier.
Before we dive into the technical details, one last note. We sometimes get asked two questions about the very nature of GWT:
In answer to the first, understand that our goal and our passion is to radically improve the end user experience of the web, which means that GWT must produce JavaScript that is maximally performant and reliable. In order to do that, we naturally want to apply a lot of optimizations to source code and catch bugs as early as possible. Both of these goals are directly facilitated by Java's static type system and the existence of great Java IDEs. That is why we, dispassionately, chose to center GWT on Java technologies. That's it — no fodder for language wars here.
In answer to the second, it is perfectly reasonable that some developers, upon first hearing about GWT, assume that it is a sort of "walled garden of abstraction" that forever locks you into Java development and prevents you from using or integrating with handwritten JavaScript. Nothing could be further from the truth, which is a great segue...
You can easily combine handwritten JavaScript directly into GWT code. It's all JavaScript in the end, of course, so why not allow GWT developers to mix-and-match in any way that's useful? That's what JSNI is all about. It's named similarly to the Java Native Interface (JNI) because it uses the same basic idea: declare a Java method "native" and then use another language to implement it. In the case of JSNI, that other language is JavaScript.
JSNI is useful to create a reusable abstraction on top of functionality that is most naturally expressed using JavaScript syntax rather than Java syntax. For example, regular expressions are pleasantly concise in JavaScript, so you can use JSNI to make them directly available in your GWT code. Suppose you wanted a method to flip someone's name around such that their last name comes first, for example turning "Freeland Abbott" into "Abbott, Freeland". (Admittedly, this example is an I18N nightmare.) You can create a short JSNI method to do this:
// Java method declaration... native String flipName(String name) /*-{ // ...implemented with JavaScript var re = /(\w+)\s(\w+)/; return name.replace(re, '$2, $1'); }-*/;
Notice that the method body is really just a glorified Java comment, enclosed by the special tokens /*-{ and }-*/.
/*-{
}-*/
You can go the other direction, too, calling a Java method from JavaScript. Suppose we modified the example above to invoke a callback instead:
package org.example.foo; public class Flipper { public native void flipName(String name) /*-{ var re = /(\w+)\s(\w+)/; var s = name.replace(re, '$2, $1'); this.@org.example.foo.Flipper::onFlip(Ljava/lang/String;)(s); }-*/; private void onFlip(String flippedName) { // do something useful with the flipped name } }
Naturally, you can access any sort of external JavaScript code from within a GWT module. For example, if your HTML page looks like this:
<html> <head> <script> function sayHello(name) { alert("Hello from JavaScript, " + name); } </script> <-- Include the GWT module called "Spiffy" --> <script src="org.example.yourcode.Spiffy.nocache.js"></script> </head> ...
Within your Java source, you can access the sayHello() JS function through JSNI:
// A Java method using JSNI native void sayHelloInJava(String name) /*-{ $wnd.sayHello(name); // $wnd is a JSNI synonym for 'window' }-*/;
The GWT compiler inlines the extra method call away, so calling the sayHelloInJava() method in your Java source is no more expensive than calling sayHello() directly from handwritten JavaScript.
sayHelloInJava()
sayHello()
You can even create JavaScript-callable libraries from your GWT code. This is a pretty neat trick:
package org.example.yourcode.format.client; public class DateFormatterLib implements EntryPoint { // Expose the following method into JavaScript. private static String formatAsCurrency(double x) { return NumberFormat.getCurrencyFormat().format(x); } // Set up the JS-callable signature as a global JS function. private native void publish() /*-{ $wnd.formatAsCurrency = @org.example.yourcode.format.client.DateFormatterLib::formatAsCurrency(D); }-*/; // Auto-publish the method into JS when the GWT module loads. public void onModuleLoad() { publish(); } }
You can then access this GWT-created functionality from within any HTML page or another JavaScript library:
<html> <head> <-- Include the GWT module that publishes the JS API --> <script src="org.example.yourcode.FormatLib.nocache.js"></script> <-- Write some JS that uses that GWT code --> <script> function doStuff() { alert(formatAsCurrency(1530281)); } </script> </head> ...
Using JSNI, you can freely mix handwritten JavaScript, external JavaScript libraries, and Java source code in any way that you need to. That's what we mean we say GWT isn't a walled garden of abstraction and that you can adopt GWT incrementally into existing web apps. And, best of all, you can debug all the Java code using the Java debugger of your choice.
To learn more, check out JavaScript Native Interface in the GWT Developer Guide. Better yet, let GWT compiler architect Scott Blum explain it to you himself.
As you may know, the Google I/O conference came to town last month and saw excited developers and lots of great sessions. It was a blast, and I had the pleasure of meeting some of our developer community members in person, which for me was the icing on the cake. Thanks to all who came to the event!
For those of you who may have missed the Google I/O conference, we're happy to report that the presentations and slide decks have been posted and are now viewable online!
You can check out the full presentation playlist here. We've also created a GWT session playlist if you're only interested in GWT-related material.
Here are some recommendations for sessions you might enjoy:
I'm excited to report that there are some fresh new links on our download page leading to a release candidate of Google Web Toolkit 1.5.
Since the previous release of GWT, we've seen a lot of really great applications that demonstrate what is possible when you are able to focus on the user and stop worrying so much about browser quirks and other Ajax obstacles. Inspired by what we have seen so far, we have continued to concentrate our efforts on enabling developers to use their existing tools to create web apps that users enjoy. GWT 1.5 takes this commitment even further with exciting new features and over 150 bug fixes. And, like all GWT releases, most of the benefits are just an upgrade-and-recompile away.
We've gotten very positive feedback from early adopters and here is what they are most excited about:
Java 5 language support It feels good to finally close out our most requested feature. GWT developers can now freely use the modern Java syntax including generics, enumerated types, annotations, auto-boxing, and so on.
New compiler optimizations increase performance With this release of GWT, we're happy to announce that our compiler produces faster code than you would write by hand! How's that? A bunch of new compiler optimizations allow us to efficiently inline method calls, even through many layers of indirection. Translation: all the nice abstractions and clean design work that are essential to maintaining a large code base melt away in the compiler's output, giving your users the fastest possible experience. By contrast, if you were writing JavaScript by hand, you'd have to choose between writing good code and writing fast code — and when your application got to a certain size, maintainability would make the second choice impossible. With GWT 1.5, you don't have to compromise; just write good code and let the compiler make it fast.
JavaScript Overlay Types This further enhances GWT's interoperability with the underlying JavaScript layer. “Overlay type” is a new term we're using to describe the ability to model JavaScript objects as strongly-typed Java instances with no additional runtime cost. Overlay types make it easy to provide fine-grained interop with handwritten JavaScript libraries as well as providing an optimal way to make JSON structures directly accessible to GWT code.
High-performance DOM API Up until GWT 1.5, we've concentrated mostly on Widget-level APIs, and until the advent of overlay types (above), direct DOM programming wasn't particularly convenient. GWT 1.5 goes beyond "convenient" and well into "elegant" with an entirely new DOM API that enables type-safe, low-level DOM programming that will be both comfortable to DOM experts and free of any runtime overhead.
Default visual themes Several default visual themes are now available by default so that developers get an attractive UI out of the box and have a good starting point to create their own custom styles in CSS.
To find out more, download the release candidate and join us in our mission to radically improve the web experience for users. And as always, we are eager to hear what you think so feel free to give us feedback in the GWT Developer Forum.
Background
In the spring of ’06 our team set out to build a general purpose geographic information system capable of presenting massive amounts of location-specific data in a user friendly interface. Our resulting product powers MapEcos.org, launched last November. MapEcos provides pollution data and information on pollution improvement efforts for over 23,000 industrial facilities across the United States. Our team built MapEcos along with business school faculty at Dartmouth, Duke, and Harvard as both a public service and a vehicle for academic research. We organize EPA data in a way that allows the public to learn more about the facilities, companies, and industries that affect their local communities, states, and the US as a whole. In addition, we encourage facility managers to post information on MapEcos about their environmental improvement efforts.
The Google Web Toolkit is a critical component of our web application (and, while we won’t address it in great detail in this post, the same should be said for the Google Maps API). We are pleased to be able to share some of our GWT thoughts and experiences with you:
Java wins over JavaScript: For a few months, we attempted to implement some of our low-level map features in JavaScript. We were wasting our time. As a language, Java doesn’t suffer many of the idiosyncrasies and complexities which can make JavaScript programming complicated, tedious, and unproductive. Our overall productivity increased dramatically as we began to re-implement and expand previously written JavaScript features in Java; we re-did months of work in a few weeks. Now we are able to share code between our client and server applications. The ability to use standard Java debuggers to identify problems in client code is also a noteworthy plus. In short, we find that GWT (nearly) brings the desktop application programming experience to the web.
As simple as necessary but no simpler: GWT is versatile. UI components are well thought out and implemented and often sufficient for our needs. While the toolkit provides useful high level abstractions, it allows us to implement low-level solutions in unusual circumstances. We use GWT’s DOM abstraction for low-level tweaking when necessary (e.g., to force GWT elements to appropriately overlay elements drawn by Google Maps) and we implemented our wrapper to the Google Map API using JSNI (Note: there is a fairly comprehensive open source maps library for GWT which might allow one to avoid JSNI altogether, depending on the needs of the mashup).
JSON and XML are well supported: We wanted to be able to present dynamic content on our map that wouldn’t necessarily come from our own back-end (i.e., the web server for the map application). By separating our lightweight map application server from the server instances that provide the MapEcos data, we are able to scale to support site load. GWT’s JSON and XML support made our job easy. The MapEcos data servers provide marked-up content containing facility, company, industry, and geographic data to a map application that doesn’t know much about the data it displays (we note that there are some security gotchas to avoid when providing this level of flexibility). Granted, JSON and XML aren’t unique to the GWT framework, but working with these standards on the client-side of an application has never been easier.
Oh, the time that we’ve saved: GWT does away with the idiosyncrasies of JavaScript without perceptibly compromising functionality or performance. More importantly, because it’s both powerful and easy to use, the GWT framework frees up valuable development time and allows us to direct our limited energy to our most pressing needs. As a result, we feel that the Google Web Toolkit has helped us build a better site.
We encourage you to take a look at MapEcos and learn more about environmental performance in your community. Comments welcome at info@mapecos.org.