Introducing T3: Enabling Large Scale JavaScript Applications

When I joined Box in 2013, the web application front-end was in a typical state for a fast-growing company - what had started out as a small codebase maintained by a few engineers had grown into a massive codebase maintained by dozens of engineers. This meant that new features were built on top of old ones and engineers feared making changes to the code because no one was sure which features the changes would affect. There were tests to help with this, but they were unreliable due to the tightly-coupled nature of the code.

My team, Front-end Frameworks, was tasked with getting our JavaScript into a better state.

To solve these problems, we created a new JavaScript framework called T3. T3 is short for "take 3", a nod to our two previous attempts to build a JavaScript framework for our web application. T3 is different because it isn’t an MVC framework like the other attempts. Instead, T3 builds on the concepts of Scalable JavaScript Application Architecture to create a loosely-coupled, model-less system for building large JavaScript applications. Our goal was to encourage our engineers to write small, single-purpose components. We believed that doing so would have positive trickle-down effects on all aspects of development.

T3 forces you to make a decision about the type of component you're building so that everything falls into one of three categories:

  1. Services - Libraries that provide additional utilities for the application to use. Examples: cookie utility, URL encoder/decoder, popup menus.
  2. Modules - A specific area of the web page rooted in a single element. Modules may use services to complete their tasks, but modules may not directly reference other modules.
  3. Behaviors - Mixins for modules, intended to allow auto-wiring of events that are shared by multiple modules. For example, intercepting link clicks to perform Ajax navigation. Behaviors may use services to complete their tasks but behaviors cannot directly reference modules or other behaviors.

We found that almost everything we build fits into one of these three components and the ability to mix and match them is powerful enough to create many different types of user experiences. Furthermore, there's nothing preventing us from using Backbone, React or another framework in addition to T3, if we so desire. T3 really just helps better organize individual code while allowing our engineers to piece together a full client-side stack out of whatever they want.

After a few months of using T3, these were our results:

  • We averaged 80% code coverage of T3 components vs. 60% for legacy JavaScript. This happened organically, without any additional education around testing. T3 components are just easier to test, so engineers wrote more tests on their own.
  • Several teams reported being able to implement new features much faster.
  • We eliminated the "what goes where" problem, so when a change needed to be made, engineers knew exactly where to make it.
  • We incrementally converted and tested parts of pages. Since T3 can work alongside other frameworks, it was easy to start creating and converting components without stopping to rewrite the entire client-side.

Today, we're happy to open source T3 so other teams who are building large-scale JavaScript applications can take advantage of it. We've already been using T3 in production for 18 months and our web application will be fully converted to T3 this year, so you can be assured that T3 is stable and reliable. For more information, see our GitHub repository and t3js.org.