Some of the best startup stories started with a hack. It may not be high tech, but simple solutions get a good product off the ground.

When Betterment was founded, Flex was the obvious choice. With a founding team of four, we needed a product that would help us create a revolutionary investment platform, in the simplest manner possible. Flex may be out of favor in engineering circles today, but it helped birth Betterment.

Here’s what we liked, why we moved on, and how we did it:

Why Flex?

We wanted to build an immersive user experience with a responsive interface, interactive graphs, and of course a natural and intuitive feel. It had to be a web application that felt like a desktop application, and in 2008 – with HTML5 only on the horizon – there weren’t enough mature javascript frameworks or browser support for our vision.

Flex offered a robust framework to quickly spin up a rich frontend application. It came with a decent set of UI widgets, a charting framework, a robust view/sprite hierarchy, a drawing API, form validation, and asynchronous server communication. Essentially, Flex is a huge monolithic framework with almost everything you need to build a desktop-like web application quickly with no cross browser headaches.

It’s Not You, It’s Me

As the years went on, support for HTML5 strengthened and Flash was looked upon as a dying technology. Flash player execution was heavy, expensive for clients, and had little to no mobile support. Once Adobe officially announced they’d be dropping support for mobile flash back in June, we knew it was time to move away from this closed-source behemoth.

The downsides? We’d lose dead-simple cross-browser support — including the infamous IE6 — but we’d be able to support iOS and Android devices. We’re a tech company. Adapt or die.

What We Kept

There were some things that we really liked in Flex from a development perspective that we didn’t want to lose. So we started looking at some MVC javascript frameworks. First, we looked at Sencha’s Ext JS. It seemed very feature rich, but too heavy and rigid. We weren’t sold that we could make the app feel like our own. Also, it’s not free and is created by a company, which means it’s proprietary technology just like flex.

We looked at Ember.js, which also felt monolithic but not mature enough. We eventually decided to go with Backbone.js because it is compact, integrates well with other frameworks, was open source, and had a large and growing community. In fact, the backbone source is only 1,400 lines of javascript.

Backbone was great when it came to defining models and having them communicate with our RESTful backend, but when it came to views it was lacking. In order to create modular views that we could inject and nest, we’d have to write a lot of boilerplate jquery code. In addition to this we still had the problem that a lot of javascript applications face: making sure all your code doesn’t end up in one file. We needed to modularize our code into manageable files with an organized folder structure. Marionette.js and Require.js were the answers to both these problems, respectively.

Require.js

Require.js breaks your code up into modules. Each module defines its dependencies and returns the results of a callback function:

 Javascript |  copy code |? 
01
02
user.js
03
define(
04
[
05
"jquery",
06
"underscore",
07
"backbone"
08
],
09
function ($, _, Backbone) {
10
return Backbone.Model.extend({
11
url:/user’,
12
 
13
// define functions and other stuff here for user
14
});
15
});

This allows us to create a dependency tree that you’d see in languages like Java, Actionscript or Ruby.

In the example above, this file, user.js, calls define which takes an array of dependencies and a call back function; here we need three dependencies for this file. Once they’re loaded, the callback function is invoked with the three dependencies as arguments. And as you can see it defines and returns a Backbone Model subclass for a user. We could then require the user.js file in another javascript file and the User class would be passed to the callback function in that file.

You only include one script tag in your index.html, it links to a entry point script that kicks off the require process to load all scripts, and then runs a callback function.

index.html

 Javascript |  copy code |? 
1
2
…...
3
 
4
…...
5

main.js

 Javascript |  copy code |? 
01
02
require(
03
[
04
"jquery",
05
"underscore",
06
"app",
07
],
08
function($, _,  App) {
09
      $(function() {
10
              App.start();
11
       });
12
});
13

In main.js we call require rather than define, this is what starts loading all the scripts. After all the dependencies are loaded, the callback function is invoked and in there we wait for jquery to be ready and then we start our Marionette application.

Marionette.js

Marionette provides useful subclasses of Backbone’s View class; these subclasses give a lot of functionality that is lacking in Backbone Views. The biggest value-add is the Layout subclass, which allows you to define regions in your view that are containers for other views. This allows you to nest views inside of views without any boilerplate code.

 Javascript |  copy code |? 
01
02
define(
03
[
04
"jquery",
05
"underscore",
06
"marionette",
07
"views/transfer/depositView",
08
"views/transfer/withdrawView”
09
],
10
function ($, _, Marionette, DepositView, WithdrawView) {
11
    return Marionette.Layout.extend({
12
       template: "transfer/transfer", // loads template from  templates/transfer/transfer.html
13
 
14
        regions: {
15
            depositArea: "#depositArea",
16
            withdrawArea: "#withdrawArea"
17
        },
18
 
19
        onRender: function() {
20
               this.depositArea.show(new DepositView());
21
               this.withdrawArea.show(new WithdrawView());
22
        }
23
    });
24
});
25

Here we define two regions, depositArea and withdrawArea. Once the TransferView’s template is rendered, we inject a new DepositView and WithdrawView into these 2 regions. The regions are just empty divs, waiting for content to be put in them. Here is the template file for this TransferView: transfer.html//          <![CDATA[

Deposit or withdraw money

// ]]>
// ]]>
// ]]>
// ]]>
// ]]>
// ]]>
// ]]>
// ]]>
// ]]>
// ]]>

Marionette also provides two other useful Backbone.View subclasses, ItemView and CollectionView. Together these two reduce boilerplate code around rendering Backbone Collections. When creating a CollectionView you simply provide a Backbone collection and an ItemView subclasses with which to render each model in the collection. The CollectionView takes care of the rest, binding view updates to events triggered by the collection.

accountsCollectionView.js

 Javascript |  copy code |? 
01
02
define(
03
[
04
"jquery",
05
"underscore",
06
"marionette",
07
"views/summary/accountView"
08
],
09
function ($, _, Marionette, AccountView) {
10
return Marionette.CollectionView.extend({
11
itemView: AccountView
12
});
13
});
14

summaryView.js

 Javascript |  copy code |? 
01
02
define(
03
[
04
"jquery",
05
"underscore",
06
"app",
07
"marionette",
08
"views/summary/accountsCollectionView"
09
],
10
function ($, _, App, Marionette, AccountsCollectionView) {
11
return Marionette.Layout.extend({
12
 
13
regions: {
14
accounts: "#accounts"
15
},
16
 
17
onShow: function() {
18
 
19
// create collection view, pass in accounts collection
20
var accountsView = new AccountsCollectionView({
21
collection: App.user.get('accounts')
22
});
23
 
24
this.accounts.show(accountsView); // inject collection view into region
25
}
26
});
27
});
28

In the two files above, we define an AccountsCollectionView which uses the AccountView as it’s itemView class. In the summaryView when we instantiate a new AccountsCollectionView and pass in a collection, it will render an AccountView for each model in that collection, thus rendering a list of all the users accounts.