Monday, January 30, 2012

Web dev with two turntables and a microphone

There is a development style for web-based user interfaces a little up the road, from the habitations and the towns we know. It is not new or unusual, but I think it needs to be spelled out a bit since it is the "why" behind tools like RequireJS and volo, and it is what I expect to be the defacto development style for the future, particularly for mobile web-based apps:

Do not use servers to build web-based user interfaces.

What do I mean by "do not use servers"?
  • Servers should be restricted to providing data API services only.
  • A simple web server to serve static files for UI can be used, but it is only to support serving static resources that can be heavily cached. The UI serving is strongly decoupled from the API services.
There is a JavaScript corollary for this approach, and a "red pill" variant, but first more on the benefits.

Design advantages

This separation of concerns gives the following benefits:
  • Better scaling characteristics. Static web UI can be offloaded to Content Delivery Networks (CDNs) and heavily cached. Even if the UI is served from the same domain as the data API services, the UI can be served from separate, simpler servers that can be scaled independently from the API servers.
  • Forces good API design. Getting your data from a network API enforces strong constraints on what are data needs and what are UI needs.
  • Better offline. This is really critical for mobile UIs. You can set up the UI to use AppCache and give the user feedback if the network is not available.
  • Better division of labor between teams. Front end UI developers and back end data developers can have different personalities and scaling concerns. Having a strict API contract between them allows them to each focus on what they do best.
Ideal use cases

Basically, the future:
  • JavaScript-driven web apps. Message-based/social applications, maps, games.
  • Mobile web. Sites served to users on mobile devices, devices where connectivity is not always guaranteed.
  • Installed "web apps". Phonegap/Cordova-backed apps, or something like Mozilla Web Apps that will allow you to install your web app on an OS so that it has its own desktop icon and may launch the UI from files on the local computer/device.
Use cases that may not fit

Some content-heavy UIs, like a CMS or blog, might work well as a PHP/Rails/Django/Node app where the data (content) is injected into the page. This is primarily to satisfy search engines or deal with older browsers that, for instance, do not support the history API.

However, for more static content, like blogs, much of the content can be generated once and saved to disk, and could still fit into the "serve static resources" approach. memcached is often used to achieve this effect.

So even for these cases, see how much a data API can be used to generate static output for the UI instead of doing a runtime merge for every request. It will make it easier to deal with the request-hungry googlebots, and enable the other benefits above.

Of course this will not work for everything, but for the next project, see if it does fit.

The JavaScript corollary

Any tools you need to build the UI should be written in JavaScript.

You are already using JavaScript in the page, might as well use it for your tools. It makes it easier for front end developers to share and improve the tools.

While we may not be at this end state yet, we can now get there now with Node.

Wait, isn't Node a server? It is an event-based JavaScript runtime that happens to have good networking and file I/O support. You could use it to build an API server, but you can just treat it as a command line tool environment. That is how the RequireJS optimizer and volo use Node -- a bootstrap for single file command line tools.

By using, you can set up tool actions to occur on file changes, no need to run the UI through Node.

If you prefer sugar like CoffeeScript and SASS-like systems, go for it. Just use command line/watch tools to use them. And ideally the tools are written in JavaScript. If they are not, that is OK, consider JS the next time a rewrite is in order. Or better yet, create JS-backed versions of the project now and use it for future development.

You do not need to subscribe to this corollary, the big step is to just embrace serverless UI design.

The red pill

If you want to go with the "use JS for tooling", you can go a step further:

Avoid tools/dependencies/sugar to help you make UI, and embrace plain JS/CSS/HTML. It is all you really need to know. Sure, you need some tools around that to help with source code management/deployment, but those are needed in any case. You can simplify by avoiding abstractions.

Of course I still support you if you want the extra sugar or tools to make web development more palatable for yourself. I can see using tools like bicycles to help you get places. Even if using plain JS, it is helpful to use some libraries to smooth over browser differences. However it is great to keep the extra gear you need to understand and maintain to a minimum.

The tools I make will focus on getting as close to the JS/CSS/HTML bare metal as possible, but they should also work well if you want to go up the abstraction ladder.

RequireJS and AMD modules are about sticking to the JS metal but still provide a basic capability missing in JavaScript. AMD is a great "transpile" target if you want sugar on top of AMD. volo is about getting your web project set up easily with the dependencies you choose to have.


Serverless UIs supported by JS-backed tools are where it's at.


khs4473 said...

Hi James,

Definitely agree with respect to using plain old HTML/CSS/JS and avoiding the sugar!


Anonymous said...

Are you referring to full-blown webapps or all types of web pages? You shouldn't be generating your page content with JS if you care about SEO, accessibility, etc.

James Burke said...

Anonymous: more towards the webapps spectrum. The "Use cases that may not fit" section talks a bit about other use cases, but I agree it is not a fit for everything.

Jacob said...

Well, if you really want your RESTful services for, say, Wordpress, you can just dump/activate some plugins.. Then parse the JSON accordingly. I'm looking into something like this.