My Formula One site Fantasy-F1.Net is currently looking rather tired and dated – it is after all a six year old UI design that was first implemented in Microsoft ASP and then re-written in JSP/Struts when Ajax was a cleaning product. So some months ago I took the decision to completely re-design and implement the user interface using JSF and Ajax. As I’ve been working with JSF exclusively at work for about a year it was a logical extrapolation to use this to deepen my knowledge of JSF and, in particular, write some custom components. The idea of turning the user interface into something richer, and more interactive, is very attractive, and I want the users of the site to react with a ‘wow!’ and want to show their friends.
I’ve been exploring the custom component landscape and it seems pretty clear that while there are lots of nice DHTML components available, an increasing number supporting asynchronous updating from the web server, they are by and large written with the assumption that the browser can handle the added complexity, and that the browser’s connection to the internet can handle the additional bandwidth.
However, even in a well-connected country this isn’t always a good assumption for a web site targeting the general public. Visit a DHTML web site from a big web presence such as the BBC and they acknowledge this with a link to a low bandwidth version (in a full browser) and by defaulting to a mobile version on platforms like the iPhone. In the worst case scenario this means that the web development team could end up writing multiple versions of the web site – with DHTML it isn’t quite as simple as using XML and XSLT to render for multiple scenarios.
Moving back to JSF then, what design decisions can we make when sketching out a component that we anticipate will use both DHTML and asynchronous updates, but degrades gracefully when the need arises?
In architectural terms, implementing DHTML components impacts scalability, as the end user is downloading additional content – quantities of JavaScript code to enable the Domain Object Model to be modified on the fly without requiring a round-trip to the web server. Add in asynchronous behaviour – JavaScript components making calls back to the web server and modifying the displayed page as a result – and you add in further load on the server and, incidentally, you could start to see a significant load on the client as well depending on the efficiency of the JavaScript. Here are a few tips to consider when designing your JSF application that will help mitigate these potential issues.
Ensure that the JavaScript code you are deploying has been compressed and appropriately packaged.
By this I mean run the .js files through a utility that will remove all the ‘fluff’ that makes the code easy to read and maintain: comments, blank lines, leading and trailing spaces for starters. There are a number of utilities available to do this, and some will go further than others in the quest to reduce the size of a download.
In packaging terms, one .js file may be the best approach (the user has just one download the first time they visit your site), but if there are significant quantities of script that are only used on certain pages it is worth splitting these out so that they are loaded only when necessary.
Do you want your site to work when JavaScript is turned off? This is a key requirement of the WAI accessibility guidelines (and a small but significant percentage of mobile browsers), and something that must be decided early in the design process. It is feasible to design JSF components that have a default, simplified behaviour when JavaScript is turned off. Naturally your site won’t look as good but you’re making it available to people using simplified browsers and screen readers, so some access is better than none at all. Naturally, if JavaScript is turned off you would also ensure that the application doesn’t try to deliver all those .js files as well.
Moving on to the asynchronous aspects of a rich web application, consider designing your components to have both an ‘asynchronous’ mode where callbacks happen, and a ‘static’ mode, where they do not.
Consider a theoretical Twitter component. You supply it with a twitter account and it displays recent tweets from that account. The static mode of the component would simply get the recent tweets and display them when the page loads. Nothing changes unless the user re-loads the page. However in asynchronous mode, JavaScript would check back for fresh tweets every minute, updating the view as new tweets are retrieved.
Now the user could be given a UI component to turn on or off the asynchronous functionality, but it would also be possible to automate the default behaviour using an asynchronous and invisible component to measure the round-trip time (client sends a message to the server which responds back to the client), and based on that round-trip time adjust the asynchronous update frequency – or turn it off altogether. When the user turns asynchronous updates back on, the component runs again to ascertain an appropriate update frequency.
This approach of dynamically adjusting the refresh has the further benefit of helping to throttle traffic when the server is busy. Since it is the client that sends the request and times how long the response takes to arrive, it is measuring both the network latency and the latency of the web server. So, as server load increases, the server latency goes up – and the asynchronous update frequency can be adjusted as appropriate to help prevent server overload.