Skip to main content

Declarative UI and Principles of REST

Posted by jhook on September 14, 2005 at 11:21 PM PDT

I've been racking my brain lately, tossing around ideas. I've been working tons with Facelets technology with trying to push JSF into new directions, but it still sits on top of JSF. Not that there's anything wrong with what JSF does, it's really rich, almost too rich.

JSF really 'gets' the concept of a component. It allows you to mingle components and accessory concerns such as listeners, validators, and converters within the same document. Great. But...

As a carry over from JSP, you place JSF in a non-declarative environment, which means that if you are using JSP, then you must handle the fact that there could be predicate logic that may or may not include some component or some action listener for a given page evaluation (JSTL or custom tags). JSF gets around this by capturing the component models state and either storing it in the session or serializing over your precious bandwidth.

Tapestry seems to handle things slightly different such that anything that should be declarative, is, and externalized into a separate document. Correct me if I'm wrong, but Tapestry basically says that I don't want to have to worry about capturing uneccessary state for declarative artifacts, so I'm not going to put them into the 'view' where imperative logic is present. It does clean things up logically, but somewhat scatters UI concerns into multiple places. The benefit of JSF in this case is that everything can be expressed in the same document and collaborate with almost any other logic. So which is better? I don't have an opinion either way, both of them have their strengths.

Let me present the use case that has been pushing this reflection. You want to iterate over 50 products, but use AJAX to refresh only one of the products in the page. With JSF, the product iteration is a transient process-- your JSP model is different than the rendered HTML markup basically. So there's no efficient way to selectively evaluate only one product without reproducing the iterative process. Because of imperative semantics that JSF accomodates, you can only re-evaluate the component model as a whole in attempt to capture that tiny bit of state you wanted to refresh.

A really good example of my point is lets say that you are using Struts. When I request, '', it's a simple, straight Map look up to find the associated stateless action and process those parameters. Now lets apply this to JSF. Your struts-config now allows predicate logic like c:if's or c:forEaches around your action-mappings. In addition, each Action can provide logic in selection. Now, how easy is it to translate that URI to the correct Action and guarantee it's evaluated correctly? Think about it. That's what JSF and these rich component models have to deal with in managing all of that imperative overhead.

I guess I can't completely blame imperative logic poisoning declarative component models, because there's enough trouble as is translating component 'trees' over HTTP's 'flat' request string. JSF does a lot with rendering id's and names to translate those unique id's back to the component tree during evaulation.

Well, what if you were to take id management to the next step? Imagine if you were to write a truely stateless/declarative compiler, such that id management is built where given a unique id, you can 'reach into' the compiled page and selectively choose components to evaluate. Basically what you are doing by staying strictly declarative in your component models is that your framework can start to draw presumptions and inference behavior/state that doesn't need to be preserved in the way that JSF does.

Like I said before, JSF is really rich with what you can do. But it's that richness and all the possibilities it provides will also create overhead. Reading about the principles behind REST, there's a lot of genuine truths there that make me think that Struts/WebWork are partially right with being able to handle pure URI navigation. In the process, that purity allows them to inference a lot of things and produce lighter weight/stateless artifacts. There really isn't much room for that in the JSF API, but it does a really nice job of handling the fact that it can't really presume anything from its developers.

Related Topics >>