Skip to content

Instantly share code, notes, and snippets.

@dgroulx
Created June 20, 2013 16:04
Show Gist options
  • Save dgroulx/5824133 to your computer and use it in GitHub Desktop.
Save dgroulx/5824133 to your computer and use it in GitHub Desktop.

Turbolinks and Russian Doll Caching as an alternative to Client-side Frameworks

Recently The Factory graduated its second coLearning class, which means there are now twenty new developers coming in and out of the office asking all of the questions that new web developers tend to ask. One of their most common questions is one that experienced developers are also dealing with: which Javascript framework should I invest in? After all, the conventional wisdom of today is that client-side single page applications(SPAs) are the future of web development. How are we to answer their query?

One of the worst things a developer can do when gathering requirements is to presuppose the use of a particular technology. The presence of the name of a technology within a requirement is a dead giveaway of this occuring. Instead of trying to answer the question of which Javascript framework is the best way to write your SPA, lets try to understand why current web development methods are inadequate for developing modern web applications, and then explore how those issues could be addressed. But first...

History

In the beginning there was no Javascript, and life was simple. The web was fully stateless, and pages were representations of the state of the database, which served as the single source of truth. Any time the user altered state they had to perform a full request, thus keeping the entire system in sync. Unfortunately, requests were expensive operations in both server resources and user experience. Thanks to the stateless web, every request had to regenerate the entire page, which often involved many database reads of information that rarely changed.

Then came AJAX. All of a sudden, web pages took on a life of their own, becoming mini applications with their own state. Upshot: no longer was it necessary to regenerate the entire applicaiton state every request. Developers could be more fine-grained in their modifications of the page. Unfortunately, this also meant that browser state was stored in the DOM, in the view layer. Now the state of any given piece of data could be stored in many places: the database, or multiple locations on the web page. The onous was on the developer to keep these representations of information manually in sync, generally through DOM manipulation. While this style of development was non-ideal, the increase in web site interactivity was generally worth the tradeoff. However, as web pages grew from dynamic displays of information into full blown applications, the inherent problems of storing application state inside the view layer of the page became overbearing. Web applications devolved into what generally is known as jQuery spaghetti code.

This is the fundamental problem that we must address in order to create a modern web experience. The right question is not "Which Javascript framework should I invest in?" but rather "How do I solve the problem of synchronizing state in a web application with a dynamic interface?"

The Client-side Solution

Client-side Javascript frameworks provide one answer to this question. Through their two-way bindings, frameworks like Angular and Ember move state out of the view and into a model layer in the client. Thanks to bindings, there is no limit to how many representations of data occur in the view layer; the framework abstracts away the view synchronization for you. Sadly, we have still broken the fundamental model of the web. Application state is now stored in two places, the client and the server. This is not a deal breaker, after all client-server applications go back decades, and our code has improved from jQuery spaghetti to well organized and maintanable framework code. But these new Javascript frameworks are not without cost. Is it absolutely necessary to throw out our battle tested, refined over years server-side frameworks, languages, and toolchains in favor of brand new, poorly documented, under heavy development client-side frameworks that are still finding their way? Even in the best case scenario, SPA client-server style applications are more difficult to reason about than dumb-terminal style stateless applications. What if we could solve the fundamental problem of state synchronizing in a different way?

Lifecyle of an Application Request

What if we could return to the pre-AJAX model, where the only representation of application state was the database, and return to a more stateless web? Lets begin by comparing the request cycle of a tradional web application to a client-side SPA.

Traditional Server-side Application
Request -> Many Database Queries -> Render HTML -> Browser parses JS, CSS, and HTML -> Done

Single Page Client-side Application
Request -> Fine-grained Database Queries -> Render JSON -> Browser synchronizes views with query results -> Done

Logically the flow of each application is similar, however the full server-side request takes too long to deliver an acceptable user experience. If one could speed up a few crucial of the stages in the server-side application pipeline, server-side style development again becomes a viable approach for delivering modern web application. What we need to accomplish is:

  1. Fine-grained database queries while still rebuilding the entire system state on each request.
  2. Bring HTML rendering time inline with JSON rendering times.
  3. Speed up the JS/CSS/HTML compile step

The Turborussian Solution

Enter two new features of Rails 4: Turbolinks and Russian Doll Caching. On their own they are interesting, combined they offer to fullfill the promises of client-side frameworks while still living the dream of a pure stateless application. All while never leaving the comfort of Ruby.

First problem: too many database queries in a traditial stateless request. Since each request must rebuild the entire page, the entire system state must be queried from the database. However, very little actually changes in between requests. This is a job for caching. Rails has had support for caching database requests for awhile now, but Rails 4 takes request caching a step further. Instead of caching database queries, Russian Doll Caching caches the rendered HTML view associated with a model and all its dependants. Most importantly, Russian Doll Caching automates the process of invalidating and rebuilding the cache, making it transparent to the developer. This technique takes advantage of extensive knowledge of how the view is structured to keep database queries to a bare minimum.

Second, HTML rendering speed. Again Russian Doll Caching to the rescue. By caching the rendered HTML views, caching turns rendering HTML into mostly a simple string concatination whose runtime is on the same order as rendering out JSON.

Third, rendering the request response. For most websites, the majority of time spent rendering a page is spent in the process of compiling Javascript and CSS. This is where turbolinks comes in. Turbolinks treats every request your application makes as an AJAX request. However, instead of receiving HTML snippets or JSON to be inserted into the document via tricky DOM manipulation, Turbolinks returns the full page body. This leads to a page that feels as if it is making AJAX requests to update tiny snippets here and there. In fact, the application is rendering full pages in the traditional server-side manner while providing a seamless experience to the end user. Considering the amount of gyration that client side frameworks go through to keep their various views in sync with the data model, the performance of this technique is again on the same order as the client-side approach.

Lets revisit the flow of a request through our new Turbolinks/Russian Doll Caching powered application:

Turborussian Powered Server-side Application
Request -> Fine-grained Database Queries -> Return cached HTML/miniamal rendering -> Browser parses HTML -> Done

The end result is a request whose total request time is on the same order as a request made by a client-side application, only now with reduced client state and back to having a single source of truth in the database, not to mention removing the need for an entire framework.

Conclusion

Turborussian style development is one of those classic Rails technologies that gives 90% of the result for 10% of the effort of alternatives. When deliberating how best to modernize your web development, be sure to give this technique a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment