How can more layers be more efficient?

February 20, 2016

Summary: It's common that adding more layers of abstraction or indirection will make things slower. However, React and ClojureScript make web pages faster than doing it by hand -- essentially programming the bare web. The lesson is that if you choose your layers well, they can actually make your system faster.

David Nolen produced an article showing how, out of the box, using React with immutable data structures was faster than using the more common MVC frameworks, for instance Backbone. He demonstrated it using the popular TodoMVC, which is a collection of many, many, many implementations of the same basic app. When implementing the TODO app in a straightforward way, React with ClojureScript beat the others when performing lots of operations.

It's a bit of a perplexing problem. On the one hand, you've got the Backbone implementation that is a very thin layer and is manipulating the DOM directly. It's using mutable state. On the other hand, you've got React with ClojureScript. Everything in ClojureScript is known to be slower than everything in Backbone.

So it's no wonder it's a little hard to believe. But there's some facts left out of the balance above.

Before we go into those, I should mention that a lot of people argue with the results David Nolen got because he used a very uncommon use case that the other apps were not optimized for. He added a large number of TODO items at once. But David Nolen didn't optimize his for that, either. It only reinforces the point: why is it that when the number of operations gets large, React + CLJS starts to win?

The high level is this: each of the layers that React and ClojureScript add are optimizers. Insert some optimizers in the equation and things start getting faster.

It's a bit like whether it's faster to fix your toilet yourself or to get a plumber to do it. Sure, there's some overhead of scheduling an appointment, travel, etc., but it might be faster in the long run for a plumber to do it. They know just how to diagnose the problem, where to buy replacement parts, and how to use the tools. If you did it yourself, I'm sure you could figure it out, but you'd be reading books, maybe you buy the wrong part, and your toilet might be out of commission for a while. A plumber is an optimizer that eliminates the wrong plumbing operations.

Conclusions

That's my answer to the question of how React+ClojureScript is faster than MVC and sometimes even faster than React by itself. If you add optimizers that are faster than the operations they're eliminating, it's a performance win. Virtual DOM uses quick checks to eliminate expensive DOM operations. Immutable data uses fast pointer comparison to eliminate expensive whole-tree comparisons. It's not much of a paradox that as things get complicated, the more sophisticated system starts outperforming the brute-force approach.

If you'd like to explore ClojureScript and React (through Om), I recommend the excellent LispCast Single Page Applications with ClojureScript and Om. It's an interactive course with videos, exercises, and lots of source code. It takes you from zero to single page app.

You might also like