Custom Search

Wednesday, December 30, 2009

Why most web frameworks suck

Compared to desktop GUI frameworks, most web frameworks pretty much suck. Of course, web frameworks are like editors and X window managers - nearly everybody hacks one together, so there are more available than can reasonably be known by one person. If I've missed one that doesn't suffer from the problems I mention, please let me know about it!

So consider the simple act of adding a button that arranges to run a single bit of code. In a desktop app and OO language, that looks something like:

  ActionPane.AddButton(text="Do It!", callback=DoIt, pack=LEFT)

I.e. - you tell the system you need a button, how to label it, what code to run when it's pushed, and a little bit of information about how to position it.

In a web application frameworks, getting that effect typically involves adding text to a template somewhere, then tweaking the global "routing" configuration so whatever event the user generates by clicking the button in their browser actually invokes the DoIt code. Instead of editing one file - that's the same language as the code to DoIt - you're editing as many as three files, in three languages. If you're really lucky, two of them are XML with different namespaces, so it only feels like two languages.

Having to specify the routing by hand is particularly egregious. It's sort of like having to use the windowing systems ID for the button to find the callback code for the button. No competent desktop programmer would put up with that for long. If nothing else, they'd write a wrapper function to hide that from them.

Templates are a relic of a bygone era. In the best case, you're editing XML with multiple namespaces - which is ugly enough. But there's a good chance you're editing XML intermingled with something else. In the worst case, that looks just enough like XML to confuse an XML editor, but I hope everyone is beyond that.

Apache's Tapestry manages to avoid all that by using Java's introspection facilities to find methods in the code and automatically tie them back to invocations in the templates. The downside is that this exposes all your code in the templates, which is maybe not such a good idea. The problem is that half the application uses templates that need to refer to code objects, but aren't written in code themselves.

Templates were intended to separate the presentation of the data from the code that generated it, but I've never seen a templating system that did that properly. In particular, to present a list of data items of unknown length, either the templating language has to have a method of coding a display that's repeated for the sequence, or the code has to emit bits of display control to separate items in the sequence.

The reason I call this a relic of a bygone era is that CSS was supposed to have allowed the presentation control to be moved into the style files. While everyone uses style files to control presentation, people still seem stuck with doing the actual page coding in templates. If your team is driven by non-programmers who create the template files, this may be a desirable situation. But if your team is all programmers, it pretty much sucks for them - even if they don't realize it.

If, on the other hand, the template's could be replaced by code, with the presentation controlled by CSS, a lot of problems vanish. Programmers could work in one language - the code. CSS doesn't need to reference code objects, it just needs to reference known tags, class or id values - which are part of the output data, not part of the code. This is essentially what the desktop applications are doing.

One major difference is that desktop applications have to call code to create the structures that describe the UI. The UI for web apps can be described by a simple text string. Because of this, even in tools that embed the template in the code, the template is often text or data, and not actually code. This then requires code to walk that structure, generating the text and plugging in values where it's needed. Unless the structure in question allows sharing bits between it, this makes sharing objects between different parts of the UI difficult. If the UI is described by objects with their own intelligence, it becomes easy to share those objects between different parts of the UI, even if it looks like a template structure.

Like I said, there's no fundamental reason that this can't be done - it's just that people don't. The one exception I know of is the Seaside framework. Unfortunately, it's written in Smalltalk, which is even worse about playing well with others than LISP. It's also not suitable for use with Clojure, as it's unabashedly OO.

I've spent the last few days contemplating what a Seaside like framework for Clojure should look like. I've got a rough design, and hope to have some sample code working in the near future. At that point, I'll post a design for review.


  1. Wt (pronounced 'witty') follows the convention used by desktop apps as you describe -- if you don't mind C++.

  2. This is interesting... would a controller add content to a template like this?

    output.emit( MyModel.find(ids => 1, 2, 3) );

    and then CSS create all the presentation? I'm not sure CSS is strapped enough - as it is supposed to work along side HTML, but some hybrid could be useful here.

    I hope my comment makes sense.

  3. Mike,
    You're referencing Tapestry, but the story does not end there.
    For a more "desktop-like" style of GUI development, you have at least 3 more alternatives:

    * Wicket: some people say it's "Tapestry" without the defaults (some people say it's the "subversion" of "cvs" :-) ). Wicket allows one to do desktop-like development. Templates can be used, but it's more for either the general "layouting" of your application, either when you need to create custom controls that you cannot create by just composing existing ones. All coding experience is java (so easily replaced by clojure I guess!).

    * GWT : Google Web Toolkit. The UI part is coded in java, with a subset of the java API. But this UI part is then "compiled" in javascript and the development is clearly separated into 2 layers: the GUI layer which will all run on the client's browser, and the server-side layer (and the developer has to maintain an "RCP" layer for making both layers communicate). From a clojure development perspective, GWT may seem less appealing since you cannot use its expressivity to use a more "declarative" manner of writing the GUI components. Maybe not such a big deal in practice, though.

    * Eclipse RAP: you code exactly as you would code with SWT. All the logic is run on the server, and the browser is just a "Passive View" which delegates user events to the server. Here the developer does not have to care whether the code will execute on the browser or on the server. The drawback is that you loose control concerning the repartition of the code execution between the browser and the server, so this solution cannot be as fine tuned as e.g. GWT for heavily loaded web apps. An interesting aspect is that you can easily use clojure with Eclipse RAP. And you can "single source" parts of the GUI of your application between a RIA and a RDA version. A drawback, though, is that your application will seem similar between the desktop and the web (and currently it's more "have a desktop app in your browser" than "have a web app in your desktop" approach ...). This may change in the future. And when RAP will improve, your app will also improve (e.g. RAP could offer in the future the option of using Flash, ...).



  4. Part of the point is that there is no template, there's a data structure (built in your code) that describes the page to be output. You could add content by tweaking an object that's part of that structure, either changing it's content, or changing it's CSS attributes so it's now rendered. In either case, there's no need to muck about with find and ID's in your code; you just save a reference to the object in question as you build your data structure, the same way you would with a desktop toolkit. So instead of doing:


    to add an anonymous Text widget, you'd do:

    MyOutputWidget = TextWidget(..)
    MyPage.AddWidget(MyOutputWidget, ..)

    And then later manipulate MyOutputWidget directly. The framework then takes care of rendering that to the browser, just like a desktop framework takes care of rendering it to a screen.

  5. Thanks for all the toolkit pointers. So far, RAP an Wt are the toolkits closest to what I had in mind (except Seaside, of course), but both have a bit more baggage than I'm happy with. They have pointed out things I need to keep in mind for this project.