Monday, April 16, 2007

Thoughts on GWT

I recently finished the second part of a two-part tutorial on the Google Web Toolkit. It should appear on IBM's developerWorks in the near future. I read a lot of materials on GWT during that time, including quite a few criticisms of it. So I figured I should take the time to put in my $0.02 about it.

GWT is an interesting engineering solution to a hard problem: generating standardized, cross-browser AJAX applications. What makes it unique is that it doesn't require you to understand JavaScript at all. You barely need to understand HTML even. That is really cool. But is it worthwhile?

The answer is, I don't know. It seems like a toy at times, but a really powerful toy. It's hard for me to imagine creating a real website using it, and there is really no way to even use it just for prototyping. As I understood it more though, I realized that there was a real-world workflow possible with it, and maybe that's its biggest strength.

If I were using GWT to build a real site, I would have a web designer build a complete prototype that I would check in and deploy -- as is. Ok, maybe I'd make sure that various visual components had the proper IDs or classes, since that's what GWT uses to identify and replace components. It's the replace part that is really important. The GWT runtime would replace the components created by the designer. It would replace it with JavaScript generated HTML. However, all the CSS created by the designer would be applied. So as long as the CSS was tight, then the GWT-generated component should look how the designer wanted it.

That's nice, really nice. I think having a good workflow between designers and developers is huge. Just look at what Microsoft has tried to do with Web Forms and now with XAML. Web Forms arguably inspired Java Server Faces, which is now part of the JavaEE specification. So maybe that's the real strength of GWT. Everything else is icing on the cake. That being said, here's my favorite and least favorite things about GWT.

Good Stuff
  • Debugging -- Being able to debug client side code inside Eclipse (or any IDE) is really nice. I don't know how much time FireBug has saved me in debugging JavaScript. Every JS developer I know uses it. I show those guys what it's like debugging GWT code inside Eclipse and they freak out. The Visual Studio debugger is also really nice, but it's still got nothing on a Java debugger. GWT just enables a Java debugger. Of course it's only valid for hosted mode, but that's another topic.
  • Unit Testing -- Ditto for writing unit tests. I know that there are initiatives for creating JavaScript unit tests, such as JsUnit. I've looked at it a little bit, and it's really clever. It still requires all your code to be deployed (of course.) Being able to run a unit test either inside your IDE or with an Ant/Maven target is really nice. Easier unit testing == more unit tests == better software.
  • Nice HTML Abstractions -- Really like the FlexTable for example. It's also interesting to port layout managers to HTML. I can definitely see possible conflicts with CSS though. I'm not sure what would happen if your CSS specified a position that really conflicted with the layout algorithm. I'm sure CSS would win, I'm just not sure how bad it's going to make things look.
  • RAD Tools -- Nice tools for setting up your project, etc. A lot of GWT was clearly inspired by Ruby on Rails, and this is one of the notable inspirations.
  • Architecture -- Encourages UI logic being pushed to the client. Make use of the user's computer, and offload from your server.

Bad Stuff
  • Cross Platform Problems -- All those RAD tools are OS dependent. In my experience they work really well on OSX, but are haphazard on Windows. I love OSX, but that's not good.
  • Obfuscation -- The generated JS is dense and heavily obfuscated. Maybe that is useful for Google projects, but how is it good for the average developer? It creates a dependency. If you can't debug your client code in hosted mode, you have no chance of debugging it at all.
  • No Java 5 -- It's understandable that GWT only supports a subset of Java classes when it comes time to generate JavaScript. But it's really annoying that you can't use things like the improved for loop, generics, and annotations. The annotations present a real problem if you're using Java Persistence or EJB3. An annotated entity bean cannot be passed to the UI essentially. You're forced back into a data transfer object anti-pattern.
  • Lots of boilerplate code to write -- To use a remote service, you have to write a client side interface for it (not too bad), an asynchronous version of the same interface, and the actual (server side) implementation of the interface. Then you have to write some obscure looking client side code for registering the service at runtime. Doesn't this all sound familiar? Doesn't this sound like creating remote and home interfaces for an EJB and then having to use JNDI to look it up at runtime? We all know how that turned out for EJBs.
  • Better build support needed -- Hosted mode is great, but it's kind of a pain going from hosted mode to a real deployment. GWT can't solve this completely obviously, but they can do more. Hosted mode lets you switch to a "live" mode where GWT creates a Tomcat directory and installs the web application to Tomcat. So clearly they understand the deployment issues, like exposing the RPC servlet endpoint in web.xml.
  • RPC is bad -- Ok, I'm not quite as convinced of this as I used to be, but I think it is mostly true. RPC encourages a lot of strong coupling between server and client. However, I think the distinctions between server and client are fading anyways, so this is becoming less of an issue. You're probably going to want the services called by the client to be facades to the "real" services anyways, just because you don't want your real services to be compiled into servlets (which is what happens because you have to extend the RemoteServlet class in GWT.)
Ok, so maybe I named more good than bad, but that's always the case, right? The bad things always stick out more because you spend a lot of time working around them.

I'd like to see GWT leverage Java 5 a lot more. It needs to support generics. It should not only ignore most annotations, it should use them to eliminate the boilerplate code that developers have to write and the redundant interfaces that have to be declared.

9 comments:

Tiago Serafim said...

Hi, nice article!

I want to just let you know that it's possible to get an non-so-obfucated javascript code from GWT.... you just to pass an extra parameter.

http://www.juixe.com/techknow/index.php/2006/07/15/generate-pretty-gwt-javascript/

Thanks for sharing your ideas,

Reinier Zwitserloot said...

You should probably have vetted this article with the crowd over at the Google Web Toolkit newsgroup (http://groups.google.com/group/Google-Web-Toolkit) - because you've missed a lot of handy stuff that nix most of your negatives.

1. Obfuscation: this is intentional. You can turn it off by adding -style pretty to the GWT compiler.

2. Cross-Platform: Actually, the OS X version is quite recent (since GWT 1.2); the original GWT was available only for windows and linux. I haven't heard of any problems with the tools. Which problems did you have, specifically?

3. GWT 1.4 will be released any day now. The first item on the agenda for GWT 1.5 is java5 support. Work in progress, in other words.

You can check out some actual GWT apps from this list:

http://ociweb.com/mark/programming/GWT.html#WhoIsUsingIt

Michael said...

Tiago: Thanks for the tip, that sounds very useful. Of course it makes you wonder why on earth in obfuscated the default setting?

Reiner: For the cross platform issues I experienced, check out my earlier post: http://fupeg.blogspot.com/2007/03/gwt-eclipse-and-junit-rants.html.
Good to know that Java5 support is coming soon. I will definitely check out GWT 1.4. Is there a beta of it, or do you have to build from source right now to get it?

Tassos Bassoukos said...

To alleviate some of the bad stuff, use the Googlipse plugin for Eclipse:

1. It generates the boilerplate code for services, and helps keep the async interface in sync with the actual interface. More than that, it adds wizards for projects, modules and RPC services.

2. It will auto-generate the Javascript and integrate it in the WAR archive, actual location in the archive is by default the webapp root but it can be changed if you edit a file in the projects .settings.

3. Further, you don't need to use the tomcat that comes with GWT. I've been using an external (to the GWT tools) servlet container managed by eclipse, running two JVMs in parallel; works like a charm. If you use the Generate Javascript code in the GWT shell Eclipse will automatically publish it to the server.

The entry points of services have to be specified by hand because they are decoupled by the generated javascript, and can be moved to whatever URL the developer requires (keeping in mind JS security policies, of course).

Michael said...

Tassos -- That sounds very promising. I am always paranoid about installing new Eclipse plugins. I've had bad experiences plugins that really screwed my Eclipse, but I will definitely give Googlipse: http://www.googlipse.com/ a try.

Of course I feel that the fact that people have created an Eclipse plugin to do the things I complained about, validates my complaints!

Colin Zhao said...

Michael:

Thanks for your thoughts. I believe all of us are thinking the same things as we are adopting it. Here are my thoughts about the two bads.

Build can be done/addressed with commercial plugins. Instantiations.com has a very good plugin that I like more than others.

GWT's implementation of RCP is actually very good, that it supports polymorphism. You can extends the request/response objects, so you can extend the calls. It means the client and server are very loosely coupled.

Colin

Michael said...

Colin:

As I said before "the fact that people have created an Eclipse plugin to do the things I complained about, validates my complaints!" The validation is even greater if people are actually paying for said plugins...

As for client/server coupling... I don't see how polymorphism addresses this. Let's say I write a service with a foo() method. It takes a string as input parameter and returns an integer as output. Now let's say I realize that the return object should really be a string because it could return "unbounded" for example (maybe I'm reading the maxOccurs attribute in an XML schema for example.) In any RPC system, I have to change all clients because of the change to the remote service. That's just how RPC works. GWT is no different. Polymorphism will not help with this.

Polymorphism generally encourages even greater coupling in systems. Imagine in the example above if my service had actually extended some other service. In its implementation of foo() it called a protected method on the base service. If I change that base method, I will have to change foo() and I might even have to change foo()'s signiature and thus its clients!

Polymorphism with GWT is also going to be limited by having to extend the RemoteServiceServlet class. Any service you write has to extend this class, and thus it cannot extend any other class. For example, I could not take an exsting purely server-side service and expose it through GWT. I would have to write a proxy class that used composition of my existing service.

Bryan said...

Michael: "..makes you wonder why on earth in obfuscated the default setting?"

The reason the default setting is obfuscated is because they can shrink the code down more than they could if it was human readable. I think it makes sense since you spend very little of your time debugging actual javascript, and more of you time in Java.

Great article, i enjoyed it! I'd like to hear your thoughts on 1.5.

Alyxandor said...

OOPHM...

Out Of Project Hosted Mode.

Is the shiny new GWT2 tool that lets you skip hosted mode and deploy straight to the browser of your choice. You need a browser plugin to get access to debugging and such, but it does cut compile times.

Then, GWT.runAsync, lets you DYNAMICALLY split portions of your client app into separate files for lazy-loading. Don't use a widget until the second or third click from the home page? Use runAsync, and GWT can now split it's obfuscated code to fix the "code bloat" problems some people criticize... Like a dynamic ClassLoader for JS.

PEACE!

-J