Flight was created at Twitter by Angus Croll, Dan Webb, and Kenneth Kufluk, along with other members of the Twitter Web Core team. A full list of the team involved in the development of the open source project is available on Flight's GitHub page at https://github.com/flightjs/flight.
Flight was created to provide a reliable, extensible framework for web applications, specifically to address performance and maintenance issues on the twitter.com website.
It is designed to obviate the need for a rigid model or view and the boilerplate that entails, allowing rapid development without sacrificing maintainability.
Flight piggybacks on DOM to provide application structure and utilizes DOM events to act as an interface between components. A simple API provides constructors for components and mixins and access to DOM nodes and events.
Component instances are attached to DOM nodes (known as the component's root node). Events triggered within a component are initiated on the component's root node and bubble up the tree using the standard HTML event model.
By default, a component listens to events on its root node. As all events received on that node must have come from either the component's root node or from nodes within its DOM subtree, it can be sure that the event is relevant to itself (that is, all events triggered on nodes within a particular form element would be relevant to the component controlling the form).
Components may listen to events on specific nodes within the component's DOM subtree, but outside of that, it can only listen to events on either the document or the window and has no knowledge of the rest of the DOM.
If a component was to trigger an event on its root node, components attached to nodes further down the DOM tree would not hear that event. Thus, if we were to attach a component to a specific input element (child) within a form (parent), the input would not receive events triggered on the form, making it difficult to keep the child informed.
The best solution to this problem is to rethink the whole parent-child concept. In Flight, components are not intended to instantiate other components. Application structure in Flight is almost entirely flat with no parent-child relationships.
This may seem counterintuitive at first, but is in fact a major feature in making Flight scalable. By preventing parent-child structures, each component becomes truly independent and reusable. No component relies on another to do its job.
Whether through a parent-child relationship or through a direct use of an exposed API, referencing one module's methods from within another is a major cause of problems when refactoring large applications. It is all too easy to end up with spaghetti code, a complex web of interdependent modules, as seen in the following figure:
For example, a theoretical module named
TaskManager may provide a method,
get, to return a specific task.
TaskManager.get() might make sense, but think about what happens when you change the input/output of the
get method. How do you find every reference to it? How many other methods named
get are there? Is it clear that a particular method belongs to the
TaskManager module? This can become especially problematic when instances are assigned inconsistent variable names such as
It is possible to obviate some of these problems with good method naming and a good IDE but these are by no means ideal solutions.
Flight offers an alternative.
In Flight, each component has a clear, well-defined interface and is essentially unaware of the existence of the rest of the application. A component acts as an independent entity and will continue to work as intended if all other components on the site are removed.
These simple, well-defined interfaces can be exhaustively tested, ensuring that each component behaves in a predictable manner. This makes it possible to rapidly develop new features by reusing existing components and mixins, safe in the knowledge that they will behave as expected in their new environment.
In Flight, there is no concept of a model or view. Instead, data components manage the interaction between the data store and the UI, listening for UI events, and producing data events containing only what the UI requires.
The data required to determine behavior comes in the form of simple object literals with no classes and no rigid structure. This results in considerably less boilerplate code than equivalent frameworks and a total separation of data from behavior.
The missing model is not a hardship but rather an ideal.
Flight offers a minimal API, uses the DOM to provide structure, and DOM events as an interface between components. It uses a flat structure to reduce complexity and create scalable applications. It avoids rigid model-view relationships, reducing the amount of boilerplate code required.
Flight gives developers the freedom to use a variety of best practice approaches in a well-organized environment.
In the next chapter, we will see why Twitter developed Flight and also take a look at why you may want to use it on a project.