Stream Layouts

No, I'm not talking about those things full of water running down the mountainside, I'm talking about how you assemble a full HTML (or whatever) page from a webapp.  Being a Trac user, I've done a bit with Genshi, and then with Grails used SiteMesh, both of which are stream-based engines.  I'd always though the paradigm was a bit odd, and kind of inside-out, but today I realized they're exactly the right way to do things.

The basic idea is that your app generates the page body, as a full HTML document, and then it gets passed down the stream and manipulated.  Maybe it gets some LINK and SCRIPT tags added to the HEAD, or a footer to the end of the BODY.  Contrast this with the "content variable" assembly process, where your app generates a bodyContent variable which is handed to a layout to render into a full page.

What invariable ends up happening with the latter approach is a whole pile of variable along with bodyContent (headContent, pageTitle, footerContent, aboveFooterContent, belowFooterContent, etc.).  A huge mess, especially if you're using Fusebox or something like it, where you typically put your HTML in a dsp_ file and include it into a content variable, because you end up with a massive number of one-line includes, most of which are all bound to rendering a single page (i.e. aren't reused).

Contrast that with SiteMesh or Genshi, where you can package all those separate pieces up in a single packet, and let them stream out of your app to the layout engine that takes care of everything.  It might be combining your content with another app (think a portal), might be wraping it with header/nav/footer, might be restructuring it for an iPhone vs. a PC.

This doesn't come without a downside, of course.  For example your navigation isn't controlled by your application anymore, so if you're addicted to XFAs (as I am), you're kind of stuck.  For websites it's not as big a deal because you don't want your URL-space changing, but for applications it's a bit more troublesome.  This is straightforward to deal with in the opposite direction, however.  There are also some performance implications, though they're pretty trivial.

I'm trying to figure out a good way to integrate SiteMesh with CFML.  CF is just a huge burden to try and drag into the JEE way of doing things, but Railo should be far simpler.  I really don't want to use JSP for the layout engine, and while I like using Velocity, keeping to a single templating language is certainly beneficial.  Whether I'll actually have time to implement something remains to be seen, but it sure would be nice.

4 responses to “Stream Layouts”

  1. Adam Haskell

    I don't like the whole content variable thing either. Its one of those things I'd really like to "fix" in Fusebox. To date (not giving it a whole bunch of mind time share) I came up with only one idea that mildly better (in theory not practice). Registering a Page.cfc in the controller with fusebox. Then Layout.setBody() etc. It would clean up the API some and be an attempt to keep variables from floating. I guess it would also keep layout local to the app.

    Why do you think CF is a burden to drag into JEE way of doing things? Aside from its size (behemoth) how does it differ from Railo?

  2. Adam Haskell

    So lets look at the stream for a second. How does a stream work? You build up an HTML page then at the end it is transformed into something else. That's the long and the short of it right? So really instead of putting things into content variables we are putting things into HTML tags. We still end at the same place: content we want styled placed into predefined specified areas. Really the stream is more limited if we follow using the stream and nothing else (like layouts), we are required to follow a top down procedural approach to assembly. For me I want something that is as liberating as possible. I want a way I can just throw data at the view and the view is smart enough to do something with it. Now I could certainly do with with a UI Stream but I am not liberated completely b/c I am still forced to put this together in a top down approach. I suppose I don;t have to but lets be honest if all I am going to do is reagrance all my specially IDed nodes in the HTML I might as well use content variables.

    Now lets look at the layout concept some. Don't think about it in a setBody sense that's too restrictive. I look at it feature by feature of a page. So something like setNavigationDetail(Struct navTree) or setUserDeatils(User session.user). Then my layout can decide what it wants to do with that data. The beauty of this, to me, is the liberation this gives your application. Hell I could even do something like PageLayout.setBodyRender(ReaportLayout). Report Layout could be used in all my apps. Now my layout has 100% control over how my data is represented. I now have the ability to do something like: if(mode == "AJAX") Layout new AjaxResponse() else GeneralLayout(). In this instance my application can switch between a slick AJAX UI or page driven design with much less effort. Or possibly more powerful: if(browser.isMobile()) Layout new MobileLayout(browser.mobileVersion) else Layout new GeneralLayout(). I'm not saying you can not do with with UI streams but I do think this Layout approach would provide a cleaner more well defined API for someone to follow as well as allow them to produce the data in the best OO designed way without consideration to UI ordering.