Free for 90 days: Sign up now and get 90 days managed free after your first deposit. See offer details

Coming soon: our new one-on-one advice packages. Learn more

Now available: our new one-on-one advice packages. Learn more

Get your entire Smart Saver balance managed free for 3 months. Enroll today

Get your entire Smart Saver balance managed free for 6 months. Enroll today

Introducing Smart Saver: You could earn 1.83% with our low-risk investing account for your extra cash.* Learn more

Engineering at Betterment

Server JavaScript: A Single-Page App To…A Single-Page App

Betterment engineers recently migrated a single-page backbone app to a server-driven Rails experience.

Articles by Harris Effron

By Harris Effron
Software Engineer, Betterment  |  Published: April 29, 2016

Betterment recently migrated to a more simple single-page app using a UJS pattern.

As we add more features, we make the code even simpler. This framework also allows newer recruits to onboard faster.

engineering
Betterment engineers (l-r): Arielle Sullivan, J.P. Patrizio, Harris Effron, and Paddy Estridge

We recently changed the way we organize our major business objects.

All the new features we’re working on for customers with multiple accounts—be they Individual Retirement Accounts (IRAs), taxable investment accounts, trusts, joint accounts, or even synced outside accounts—required this change.

We were also required to rename several core concepts, and make some big changes to the way we display data to our customers.

Currently, our Web application is a JavaScript single-page app that uses a frontend MVC framework, backed by a JSON api. We use Marionette.js, a framework built on top of Backbone.js, to help us organize our JavaScript and manage page state.

It was built out over the past few years, with many different paradigms and patterns. After some time, we found ourselves with an application that had a lot of complexity and splintered code practices throughout.

The complexity partly arose from the fact that we needed to duplicate business logic from the backend and the frontend.

By only using the server as a JSON API, the frontend needed to know exactly what to do with that JSON. It needed to be able to organize the different server endpoints (and its data) into models, as well as know how to take those models and render them into views. For example, a core concept such as “an account has some money in it” needed to be separately represented in the frontend codebase, as well as the server.

This led to maintenance issues, and it made our application harder to test. The additional layer of frontend complexity made it even harder for new hires to be productive from day one.

When we first saw this project on the horizon, we realized it would end up requiring a substantial refactor of our web app. We had a few options:

  1. Rewrite the JavaScript in a way that makes it simpler and easier to use.
  2. Don’t rewrite JavaScript.

We went with option 2.

Instead of using a client side MVC framework to help enable us to write a single page app, we opted to use our Rails server to render views, and we used server generated JavaScript responses to make the app feel just as snappy for our customers. We achieved the same UX wins as a single page app with a fraction of the code.

Method to the Madness

The crux of our new pattern is this: We use Rails’ unobtrusive JavaScript (ujs) library to declare that forms and links should be submitted using AJAX. Our server then gets an AJAX rest request as usual, but instead of rendering the data as JSON, it responds to the request with a snippet of JavaScript. That JavaScript gets evaluated by the browser. The “trick” here is that JavaScript is a simple call to jQuery’s html method, and we use Rails’ built-in partial view rendering to respond with all the HTML we need.

Now, the frontend just needs to blindly listen to the server, and render the HTML as instructed.

An Example

As a simple example, let’s say we want to edit a user’s home address. Using the JavaScript single page app framework, we would need a few things.

First, we want an address model, which we map to our “/addresses” endpoint.

Next, we need a View, that represents our form for editing the address.

We need a frontend template for that view.

Then, we need a route in our frontend for navigating to this page.

And for our server, we need to add a route, a controller, a model, and a jbuilder to render that model as JSON.

A Better Way

With our new paradigm, we can skip most of this. All we need is the server. We still have our route, controller, and model, but instead of a jbuilder for returning JSON, we can port our template to embedded Ruby, and let the server do all the work. Using UJS patterns, our view can live completely on the server.

There are a few major wins here:

  1. Unifying our business logic.
    The server is responsible for knowing about (1) our data, (2) how to wrap that data into rich domain models that own our business logic, (3) how to render those models into views, and (4) how to render those views on the page. The client needs to know almost nothing.
  2. Less JavaScript.
    We aren’t getting rid of all the JavaScript in our application. Certain snappy user experience elements don’t work as well without JavaScript. Interactive elements, some delightful animations, and other frontend behaviors still need it. For these things, we are using HTML data elements to specify behaviors.

    For example, we can tag an element with a data-behavior-dropdown, and then we have some simple, well organized global JavaScript that knows how to wrap that element in some code that makes it more interactive. We are hoping that by using these patterns, we can limit our use of JavaScript to only know about how to enhance HTML, not how to automatically calculate net income when trying to distribute excess tax year contributions from an IRA (something that our frontend JavaScript used to know how to do).

  3. We can do this migration in small pieces.
    Even with this plan, migrating a highly complex web application isn’t easy. We decided to tackle it using a tab-by-tab approach. We’ve written a few useful helpers that allow us to easily plug in our new server-driven style into our existing Marionette application. By doing this piecemeal, we are hoping to bake in useful patterns early on, which we can iterate and use to make migrating the next part even simpler.

If we do this right, we will be able to swap everything to a normal Rails app with minimal effort.

Once we migrate to Rails 5, we should even be able to easily take advantage of Turbolinks 3, which is a conventionalized way to do regional AJAX updates.

This new pattern will make building out newer and even more sophisticated features easier, so we can focus on encapsulating the business logic once.

Onboarding new hires familiar with the Rails framework will be faster, and those who aren’t familiar can find great external (and internal) resources to learn it. We think that our Web app will be just as pleasant to use, and we can more quickly enhance and build new features going forward.

More from Betterment: 

Recommended Content

View All Resources
How We Engineered Betterment’s Tax-Coordinated Portfolio™

How We Engineered Betterment’s Tax-Coordinated Portfolio™

For our latest tax-efficiency feature, Tax-Coordinated Portfolio, Betterment’s solver-based portfolio management system enabled us to manage and test our most complex algorithms.

What’s Inside the Betterment Portfolio Strategy?

What’s Inside the Betterment Portfolio Strategy?

Explore the asset classes in Betterment's recommended set of portfolios. Then, take a look at the exchange-traded funds (ETFs) underlying each part of the portfolio strategy.

How We Built Two-Factor Authentication for Betterment Accounts

How We Built Two-Factor Authentication for Betterment Accounts

Betterment engineers implemented Two-Factor Authentication across all our apps, simplifying and strengthening our authentication code in the process.

How would you like to get started?

Your first step toward a smarter investing future starts here.

Create a Betterment account

Go ahead and join the smart, modern way to invest.

See what we can do for you

Tell us a bit about yourself, and we'll show you the benefits of investing with us.

Get a free investing checkup

Help us get a sense of your investing approach and see how you could improve.

Transfer a 401(k) or an IRA

Move an existing retirement account into a Betterment IRA.

Download the mobile app

Enjoy the Betterment experience anywhere on the go.

Search our site

For more information and disclosures about the Betterment Resource Center, click here. | See our contributors.