The Famo.us code is now publicly available on Github. I’ve been tinkering with it for the past few days on a POC: a web-based guitar tuner. This blog post will be my thoughts and feelings while developing this simple app.
When I first saw the Famo.us periodic table, I immediately opened up my Dev Tools and inspected the DOM elements flying around in front of my. I couldn’t believe that they were able to make something so graceful using a platform that was supposedly incompatible with this level of beauty. What I saw were DIVs, CSS, and changing properties. That’s when I was sure this thing was for real.
That was almost two years ago. Now that I finally have access to the source code, I’ve dug deep to figure out the “magic” behind how they make their performance so responsive. Famo.us works by ditching the DOM positioning model in favor of CSS3 transformations.
Their argument is that the DOM was made for displaying text documents, not building complex data-driven apps. Setting the absolute/relative top/left/bottom/right position works fine for displaying text. When it comes to beautiful web apps, something different is required.
Minimalism is the name of the game for Famo.us’ core code. The library is about as unopinionated as you can get.
There are two basic options that a developer can choose from when they want to start writing a Famo.us app. The first is to include it as a Bower dependency from their GitHub, then start hacking away. This is the recommended approach for pre-existing projects with a well-defined structure that want to replace the views with Famo.us.
The second option is to use their Yeoman generator to build a project for you. This is the preferred option when starting a new Famo.us project from scratch. This is the route I chose, and I was up and running within a minute.
As a side note, the Famo.us team is very receptive to feedback. I pointed out that their Gruntfile.js generated through Yeoman could be simplified with the load-grunt-config task. They pushed the change just a few days later. (This article from HTML5 Rocks on supercharging your Gruntfile is a must read for projects that use Grunt.)
The best way to learn a new library is to get your feet wet and start writing code. That is exactly what I did, and this is what I learned.
The Engine is a singleton that is analogous to an “application” object in other libraries. It is the backbone that keeps the whole show running. It handles how animations are timed, and other infrastructure tasks like that.
A Context represents a self-contained view state of the application. If this were a SPA (Single Page Application), there would be one context. If the application can switch between X multiple, distinct views, then there would be X contexts.
The Surface class allows the developer to put renderable content onto the page. It maps to a DIV, and can take in HTML, CSS, event listeners, etc. To render a Surface, they must be added to a Context.
A Modifier (StateModifier is the most commonly used) can be added to a Context before a Surface to manage how the surface is positioned. The order that classes are added to a Context matters in Famo.us. It is up to the developer to make sure that the Modifier is added before the Surface, then they need to hang on to a reference to both.
The Transform allows a Surface to be moved around a Context. This is where the CSS3 transformation magic comes into play. The Modifier allows the Transform to be changed, which affects the Surface the Modifier is bound to.
Guitar Tuner Implementation
With the core concepts out of the way, the way I’ve chosen to implement the Guitar Tuner can now be explored. The code is hosted on the Keyhole Software GitHub in the khs-famo.us-guitar-tuner repository.
All of the code I wrote for this application is in app/src. Everything else in the project was generated by the Famo.us Yeoman generator. This got me running quickly so I could focus on writing features rather than the architecture.
When the page is loaded, main.js gets immediately executed. This loads the Famo.us engine, requires the GuitarContext, and adds the context to the engine.
The GuitarContext is really a controller for the tuner itself. It contains the context that the subviews render themselves to as well as managing the strings and pick. This class manages two other controllers: StringsController and PickController.
I tried to keep the structure of it as simple as possible. The only real gotcha is that the eventing layer in Famo.us is not a mixin, so I had to implement .on() and .emit() methods in StringsController.
The second lesson I learned is that Famo.us needs to be the one that manages all DOM interaction on the page. If the code makes a change to the DOM outside of the Famo.us Engine, performance may take a hit as well as the overall appearance of the page. This means that frameworks that generate DOM behind the scenes (e.g. ExtJS) may have issues working with Famo.us. Libraries like Bootstrap should be fine since the HTML is static and well defined.
The third lesson that I learned is that Famo.us is still young. There are growing pains associated with enterprise-level software that they’ll have to go through. I’m excited to be an early adopter and member of the community to lend my experience to them during this process of growth.
— Zach Gardner, firstname.lastname@example.org