Saturday, June 14, 2008

The post wherein I trash Rails and make many new friends

So I've been coding Web UIs with this nifty port of Rails my coworker did. It's great - really great, a solid productive environment, Javascript is great to program in, and things are mostly working out well. Except when they aren't, and lately I've come to realize that the programmatic model that Rails foists on to you is not at all suitable for advanced web UIs.

When I talk about advanced web UIs I'm talking about single-page type of web apps. The goal of such apps is not to provide an progressively degraded experience, but to push the envelope of what is even possible in a browser. I'm talking about the gmails, the Google Analytics, etc.

One fundamental problem is that Rails provides a really really good server-side templating. This is great when you are doing a simple form-and-post with remoting type of application. The structure tends to lead you to an architecture where you end up passing snippets of HTML between the server and doing innerHTML replacements on the client.

The problem with this is it's hard to disentangle the server and client presentation side of things. Sometimes your server composes the text - and handles the i18n issues - and sometimes you need to compose text and DOM on the client side. The latter can happen when you are handling errors during AJAX events - you don't want to handle an AJAX error by calling the server. So now you need to pass string tables or hidden divs with your messages in the original page. This isn't a great and integrated i18n development method.

If your goal is to create a single-page client-side stateful application, you will quickly run in to the situation where you require some form of client-side UI generation. One example is dialogs - generally they use floating divs and the JavaScript APIs tend to require HTML text snippets. Your choice is to either do some kind of client-side templating, or use the server side to pre-render in to hidden elements.

The former strategy is valid, and there are many frameworks to help you. However, this does not use the strengths of Rails. You are bypassing the entire html and model binding code, tossing away major strengths and self-crippling Rails. So why use Rails?

The second strategy is also valid, but becomes difficult to manage. You tend to need unique IDs when using fieldsets, but you'll end up having several copies of the same nodes in the dom. So now you need to swizzle IDs or move elements around. If this is starting to sound like assembly language work that is because it is.

Taking the two approaches and using i18n, you now have more issues. In the client-side templating you now need to selectively download string tables and do substitution at run time to internationalize your application. There are matters of performance - extra functional calls, hash lookups, extra HTTP gets.

In the server-generated option, things get substantially more complicated. The server-side Rails i18n situation is not entirely clear, and it still doesn't provide a framework for client-side translated strings. You can do things like JSON data from the server, but you end up manually shuttling all the strings you need from the server to the client in hidden elements or script blocks. Internationalization is hard enough without doing lots of manual work by hand.

The problem isn't that Rails isn't a productive framework, or that it doesn't do what it does well - it certainly does. The problem I found is the framework leads you to writing hybrid server-generated UIs. Furthermore, the framework tends to encourage full page refreshes. It's a matter of what is easy to do - then when you are under the gun, you do what is easiest and you end up in a multi-page application (like ours) when you really wanted a single page application. The path forward is not clear, and Rails isn't really helping here.

Friday, June 13, 2008

Google I/O Videos

The Google I/O 2008 sessions are now online. Included are slides and Youtube videos of a variety of topics, including Android, Open Social, GWT, Javascript and Maps. 

If you were unable to attend, I highly recommend the videos.  

Check out GWT extreme as an exciting example of the kinds of things you can do with JS and browsers:


Tuesday, June 03, 2008

CSS Performance

I have been reading CSS Mastery lately - its a great medium/advanced guide to CSS. If you know roughly about CSS but you need serious helping turning that in to mastery, then this book is for you. The book provides both a quick introduction and specific solutions. However, the book provides advice that may be at odds with Firefox performance guidelines.

The book starts with a quick introduction, and then delves in to the CSS box model, then straight in to rounded corner techniques. It provides pragmatic advice along the way - such as what works on which browsers and making design cross-browser.

However, the book recommends avoiding the use of too many classes - calling that design "classitus". By using the descent selector you can target your styles without using too many classes. If you read the mozilla developer guide to efficient CSS, the advice there is substantially different.

The guide advises, among other things, that the descendant selector has poor performance. They recommendation is to use targeted class styles instead. This may lead to an expanded use of classes in your application, but the performance increase may be worth it. The best strategy is to measure. Since querying certain properties will block until the CSS styling is finished, you can measure the performance with code like so:

var start = new Date().getTime();
element.innerHTML = 'a ton of html and css';
var w = element.offsetWidth;
var end = new Date().getTime();
alert(end - start);

Thanks to my Nameless Coworker who shared those tips via email.

Remember: always measure before you attempt any performance optimizing. That way you can be sure your hard work has ultimately benefited the end user.

On GWT - Welcome Visitors

Hi visitors from onGWT.com! I see my lowly blog has about 30x the traffic it normally does. I guess I struck a nerve a bit.

Currently I'm still investigating GWT. I haven't started production coding, and it may be a few months before I get prod GWT code out there, but it will happen at some point.

In the mean time, I hope to post tips and hints about my GWT experience and how to achieve elegant and performant web UIs.

Monday, June 02, 2008

Google I/O recap and summary

Well Google I/O is over. Hopefully there will be another one next year - the conference was great value, and had scores of smart people talking about interesting web things. I attended in part to learn about GWT. Initially I was very sceptical about the value proposition of GWT - compiling Java to JavaScript? Get real! Programming in a static language like Java? Two steps backwards!

Despite these disadvantages, I have come full circle and I now firmly believe that GWT is an excellent platform for advanced web apps. There are a few reasons why I now strongly believe this:
  • GWT has a form of late binding - allowing differing implementations for each browser platform.
  • GWT has good optimized support (in 1.5) for overlaying Java objects on to JSON objects, providing an elegant and efficient method of consuming JSON data.
  • Excellent and complex products are being produced in GWT, the kind I'd like to develop.
  • Good abstraction over browser quirks in a optimizing manner, as well as allowing for writing code in a abstract way.
Most of the benefits are not as a result of Java, but as a result of the Java to JavaScript method. By abstracting the non-portable aspects of JavaScript and resolving them at compile-time, you get run-time efficiency without losing your abstractions.

Most JS libraries that abstract browser differences do so by adding adapter layers, or annotating the built-in prototypes to create a new development approach. However, the practical realities of JavaScript performance don't encourage the use of extra function calls or closures. Using a Prototype example:

$('ul#myList li').each(function(li) {
// do something with each list element, possibly using a closed over variable
});

While elegant, this is not nearly as performant as more basic code:
var myList = document.getElementById('myList').getElementsByTagName('li');
for (var i = 0, il = myList.length; i < il ; i++) {
// do something with each list element, no closure necessary.
}

While in theory 'each' should know about the best way to loop over an array, you also incur the cost of two user function calls, and a closure. These are not free, even as they improve the code - mis-coding loops is a major cause of bugs.

Given that most JavaScript runtimes are interpreted (we are starting to see the rumbles of VMs for JavaScript), adding extra calls and object allocations is not free. Add these up and eventually the weight of your JS application will grind browsers to a halt.

While nothing is ultimately a panacea - better tools are always better. Increasing the level of your abstractions and letting the computer do the work for you is always better. It seems like JavaScript is becoming the new assembly language - and we all know how much demand there is for assembly language programmers these days.

If you found this useful, maybe my article on making CSS performant might interest you?