Last year we rolled out a major reimplementation of the Twitter website. In addition to shifting the rendering of our page content to the server (which achieved significant performance gains), we re-envisioned the entire client-side infrastructure with a clean, robust and easy-to-learn framework which we call Flight. Today we’re making Flight available to the open source community under the liberal MIT license as a framework for structuring web applications.
Flight is distinct from existing frameworks in that it doesn’t prescribe or provide any particular approach to rendering or providing data to a web application. It’s agnostic on how requests are routed, which templating language you use, or even if you render your HTML on the client or the server. While some web frameworks encourage developers to arrange their code around a prescribed model layer, Flight is organized around the existing DOM model with functionality mapped directly to DOM nodes.
Not only does this obviate the need for additional data structures that will inevitably influence the broader architecture, but by mapping our functionality directly onto the native web we get to take advantage of native features. For example, we get custom event propagation for free by piggybacking off DOM event bubbling, and our event handling infrastructure works equally well with both native and custom events.
How does it work?
Flight enforces strict separation of concerns. When you create a component you don’t get a handle to it. Consequently, components cannot be referenced by other components and cannot become properties of the global object tree. This is by design. Components do not engage each other directly; instead, they broadcast their actions as events which are subscribed to by other components.
Events are open-ended. When a component triggers an event, it has no knowledge of how its request will be satisfied or by whom. This enforced decoupling of functionality allows the engineer to consider each component in isolation rather than having to reason about the growing complexity of the application as a whole.
By making DOM node events proxies for component events, we let the web work for us:
Mobility and testing
Each component is a module that, aside from a minimal set of standard dependencies (relevant Flight utilities and mixins), has no reference to the outside world. Thus a given component will respond to a given event in the same way, regardless of environment. This makes testing simple and reliable — events are essentially the only variable, and a production event is easy to replicate in testing. You can even debug a component by triggering events in the console.
Documentation and demo
Our GitHub page includes full documentation as well as a sample app in the form of an email client:
Flight is an ongoing and evolving project. We’re planning to add a full testing framework and make available more of the utilities that we use for the Twitter website frontend. We also look forward to your contributions and comments. We know we haven’t thought of everything, and with your help we can continue to improve Flight for the benefit of everyone.
Flight was a group effort. These folks have contributed to the project: Angus Croll, Dan Webb, Kenneth Kufluk, along with other members the Twitter web team. A special thank you to folks in the web community who took the time to review the code.