Thursday 13 February 2014

Presentation Layer: Big Pages, Small Operations

Modern web applications use Javascript to add interactivity to HTML and relay any requested changes to the data back to the server without reloading the page. This is good for the user because moving from page to page is akin to going into a different room in your house. It's fine if you are changing activity, but you wouldn't want to go to the kitchen every time you wanted to change the TV channel.

So how can we minimize moving between rooms? The answer is to divide your app into broad areas of functionality and to create one page for each. Within each of these pages you should be able to do everything you want to do within that broad area of functionality. For example, in a blogging application, you might have one page for composing posts, one for listing posts, one for editing settings and so on.

This is what I mean by Big Pages, Small Operations. My post on using Stripes for layout covers how to create a layout that is common to all your Big Pages. I recommend organising your WebContent directory into sub-directories for each Big Page, each containing js, css and JSP files specific to that page. This makes it easier and quicker to find your way around the codebase. Usually you will only work on one area of functionality at a time so if all the files are located together you don't have to hunt around all the time. 

Each Big Page will basically be one view on some data, allowing the user to see the data and perform operations on it. It's much better for the user if these operations are relatively small, each one updating the model immediately. This minimises the chance of losing data. This is what I call Small Operations. 

For the Small Operations I recommend using the following techniques:

Updating the DOM - Choose wisely
When updating the DOM think carefully about whether it makes sense to fetch data (JSON) from the server to make updates, or fetch pre-rendered HTML. For large chunks of HTML always try to use the server to generate it. Adding to the DOM dynamically should be reserved for small operations. If it turns into more than a few lines of DOM-appending JS, make an asynchronous call to the server, and let the server render HTML for you to add to the DOM via innerHTML (this is very fast).

Passing data down to the page - use Java
Make sure you get the data in the most usable way for Javascript. Do as much assembling of the data as possible in Java since this brings you better type safety, and easier error handling and debugging.

Validation - validate server-side
Always validate data on the server, even if you have Javascript validation. It might be broken for someone, or they might get round it. Never trust the client to give you correct data.

Don't break the Back button
Use a Javascript history library to keep the browser history updated when it makes sense eg: viewing some kind of paged data in the same Big Page (like tabs, or viewing full-page records one at a time).

Keep your HTML clean
Keep your Javascript separate from HTML as much as possible. Use external JS files, bind your functionality to your interface with as few assumptions as possible about the structure of the DOM. 

Event Binding
A trendy technique is to bind listen for all events on the Document or Body elements and to have some code that binds the events at runtime based on some attribute such as the style class. I recommend steering clear of this technique unless it offers tangible performance benefits to you (eg if your are adding handlers to thousands of elements). The browser already provides you with an Event API that allows you to add handlers to elements. It doesn't make much sense to replicate this in JavaScript. Also consolidating event handling code into one giant function seems like a recipe for disaster.

Avoid closure hell
I recommend using custom events to handle responses from asyncronous calls. This allows you to define your own application-specific events rather than passing handlers through to functions. This cleans up your function signatures a lot and decouples different parts of your code.  I use SignalJS to do this since it is a nice little API and doesn't have a JQuery dependency.

Form submission via AJAX
Whilst in general I would try and design your interface to avoid using Forms, sometimes it's inevitable that you need to pass a bunch or user-entered data to the server in one go. If you want to do this via AJAX, this used to be a pain, but now you can get hold of the all form's data at once using the HTML5 FormData API. See this post http://www.html5rocks.com/en/tutorials/file/xhr2/ for this and other HTML5 Ajax techniques.