There are many technical decisions to make when writing web applications. I've come back to writing modern web applications lately, and wanted to consolidate some scattered thoughts that I’ve recorded over the course of my development cycle. In particular, this post is about the set of frameworks that I found to be instrumental in developing my most recent project. I'll go over some of the most important framework types, each of which could be expanded into an article in its own right. This is not meant to be an extensive comparison of existing offerings, just a slice of technologies that I experimented with most recently.
Although my focus is on mobile first, I think that this set of technologies can be applied to web apps in general. All of my decisions and data points were made with a few requirements in mind:
- Must work well in modern browsers (iOS 5, Android 4)
Picking an MVC
The model view controller pattern has been in use in native UI app development for decades. The basic idea is to separate the data layer (storage, communication, data) from the presentation layer (UI, animation, input). There are other similar patterns such as MVVM (Model View ViewModel), but the main idea is to have a well-defined separation between the presentation and data layers for cleaner code and ultimately long-term velocity:
Picking a templating engine
Backbone.js depends on Underscore.js, which ships with a somewhat limited templating engine with verbose syntax. There are other options available, including jQuery Templates, Handlebars.js, Mustache.js and many others. jQuery Templates have been deprecated by the jQuery team, so I did not consider this option. Mustache is a cross-language templating system, featuring simplicity and a deliberate decision to support as little logic as possible. Indeed, the most complex construct in Mustache is a way to iterate an array of objects. Handlebars.js builds heavily on Mustache, adding some nice features such as template precompilation and in-template expressions. For my purposes I didn’t need these extra features, and chose Mustache.js as my templating platform.
In general, my impression is that the existing templating frameworks are quite minimal and comparable in features, so the decision is largely a matter of personal preference.
Picking a CSS Framework
How to layout views
HTML5 provides a variety of ways to layout content, and MVC frameworks provide no opinion about which of these layout technologies to use, leaving the sometimes difficult decision to you, the developer.
Generally speaking, relative positioning is appropriate for documents, but falls apart for apps. Absolute positioning should be avoided, as should tables, clearly. Many web developers have turned to the float property to align elements, but this is suboptimal for building application views, since it’s not optimized for app-like layouts, which results in many odd problems and infamous clearfix hacks.
After much experimentation with various web layout technologies over the years, I think that a combination of fixed positioning and flexbox model is ideal for mobile web applications. I use fixed positioning for UI elements that are fixed on the screen (headers, sidebars, footers, etc). The flex box model is great for laying out stacked views on the page (horizontally or vertically). It’s the only CSS box model explicitly optimized for interface design, quite similar to Android’s LinearLayout manager. For more information about the flexbox model, read Paul's article and note that this spec is being replaced by a new, non-backwards compatible version.
Adaptive Web Apps
One final section on this matter: I’m a strong proponent of creating device-specific user interfaces. This means re-writing parts of your view code for different form factors. Luckily, the MVC pattern makes it relatively easy to reuse a single model for multiple views (eg. tablet and phone).
Flipboard for iOS demonstrates this idea very well, giving tablet and phone users a highly tailored experience for each device form factor.
The phone UI is optimized for vertical swipes, allowing single hand use.
Tablet UI works well for two hands holding the device on opposite sides.
On mobile, the main way users interact with your application is by touching the screen with their fingers. This is quite different from mouse-based interaction, since there are 9 additional points to track on the screen, which means developers need to move away from mouse events when writing mobile apps. In addition, mouse events on mobile have the problem of clicks being delayed by 300ms (there is a well-known touch-based workaround). For more information about using these events in mobile browsers, see my touch events article.
How to make it work offline
For an app to work offline, you need two things to be true:
- Assets are available (via AppCache, Filesystem API, etc)
- Data is available (via LocalStorage, WebSQL, IndexedDB, etc)
In practice, building offline apps on the web is a difficult problem. Generally speaking offline functionality should be built into your app from the beginning. It’s especially difficult to offline-ify an existing web application without significant code rewriting. Additionally, there are often unknown storage limits for various offline technologies, and undefined behavior for what happens when those limits are exceeded. Finally, there are problems with technologies in the offline technology stack, most notably AppCache, as I outlined in a previous post.
A very interesting approach to write truly offline-capable apps is to go “offline first”. In other words, write everything as if you have no internet connection, and implement a syncing layer that synchronizes data when an internet connection exists. In the Backbone.js MVC model, this can fit nicely as a custom Backbone.sync adapter.
It’s hard to unit test your UI. However, since you’re using an MVC, the model is completely isolated from the UI and as a result, easy to test. QUnit is quite a nice option, especially because it allows to unit test asynchronous code using it’s start() and stop() methods.
To summarize, I used Backbone.js for MVC, Mustache.js for templating, SCSS for a CSS framework, CSS Flexbox to render views, custom touch events and QUnit for unit testing to write my mobile web application. For offline support, I’m still experimenting with various technologies and will hopefully follow up with more information a future post. While I strongly believe in the need for each class of tool (eg. MVC) outlined here, I also believe that many of the specific technologies I described here are interchangeable (eg. Handlebars and Mustache).
One more thing: On January 17th, 2012, Thorax was announced. This is a Backbone-based set of libraries very similar in spirit to what I describe in this post. I've yet to investigate it in any depth, but the name is great :)
Use a similar set of frameworks? Have a personal favorite? Think I’m missing an important type of framework? Let me know!