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.

No comments: