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

Scalable Design to Delight Customers

For web designers, this problem-and-solution goes behind the scenes of Betterment's user-friendly design.

Articles by Adam Langsner

By Adam Langsner
  |  Published: January 27, 2014

We write our web code in small pieces, or modules, so it's easy to move things around.

In this blog post, I describe how I made a component more re-usable by moving the page-dependent code out of the component and into the pages that actually use it.

advice_page_scalable_designOne of the hallmarks of using Betterment is our sophisticated web user interface. Customers can complete tasks in an intuitive and friendly way—we believe that it’s a part of our value to delight customers. (Hey, it’s one reason we’ve been called the “Apple of finance.”)

Yet as anyone who works in web design probably knows, intuitive user experience is something that goes much deeper than what customers see on the surface. Good design isn’t always about what you show and how you show it – sometimes it’s about what you don’t show. As we add more sophisticated features to our platform, we often find ourselves reusing pieces of functionality. But new contexts call for customizations—the ability to easily toggle on and off attributes of what is fundamentally the same component.

The need to do this quickly and efficiently is served by a fundamental principle: break down our code into smaller pieces, or modules, which makes it easier for us to move things around quickly. That way we can change one area without affecting others and focus more on what matters: making our customers happy.

One component, multiple locations

I recently needed to make a small adjustment to the component I had created a year ago—and I realized that I had originally designed it in a way that went against those principles. 

We used this component on our advice tab, as well as where our customers go to set up a new goal. Now, we wanted to also use it on the page where our customers go to set up their IRA rollovers. Problem was, the way I first built it, the component had too much knowledge about the page it was living on. If I wanted to use it in a new place, I had to modify it to work on the new page rather than simply dropping it on the page and being done with it. 

Consider the following simplified example, which demonstrates the problem state:

adviceView.js

this.sideBar.show(new AccountView({
    advicePage: true
}));

goalSetupView.js

this.sideBar.show(new AccountView({
    goalSetupPage: true
}));

accountView.html

<div class="goal-name">
    <span class="name"></span>
    <span class="blue-pen"></span>

    <% if (goalSetupPage) { %>
        <span class="blue-x"></span>
    <% else if (advicePage) { %>
        <span class="status <%= account.status() %>"></span>
    <% } %>
</div>

<div class="goal-contents">
    <div class="row">
        <span>Type</span>
        <span></span>

        <button class="silver change-goal">Change</button>
    </div>

    <% if (advicePage) { %>
        <div class="row">
            <span>Target</span>
            <span class="goal-amount">
                <span></span>
                <span class="blue-pen"></span>
            </span>
        </div>
    <% } %>
</div>

In the first two files we are displaying the AccountView component in the sidebar of the advice and the goal setup page. In both of these files we simply pass an option to the AccountView with the name of the page we’re on: “advicePage: true” or “goalSetupPage: true”. The AccountView handles the rest.

The third file is the HTML that actually draws the AccountView component. On the advice page in the top right we show the goal’s status (on track or off track), but on the goal setup page it is replaced with a remove icon to allow the user to delete the goal. You’ll also notice that on the advice page we have an extra row on the bottom showing the goal’s target balance, whereas on the goal setup page we do not show that.

We wanted to use the AccountView on the rollover setup page with one slight difference from the goal setup page: the Change button to the right of the goal type should be hidden.

To do this, the component would need to support a rolloverPage option and then have knowledge of how it should appear on that page. The more pages we want to use this component in, the more options we have to handle in its HTML. This is simply not efficient code! It’s not maintainable and makes it difficult to modularize our codebase.

Better way to solve this problem: An analogy

Then the right analogy came to me to help me solve the problem. Consider a restaurant to be the reusable component and its customers to be the pages where the component is used.

If our current implementation was used in this scenario it would look like this: You would call the restaurant, tell them your full name and they’d just know exactly what you wanted. The restaurant would have to maintain a book with all of their customers and what they wanted to order.

But in reality, this just doesn’t work very well. The restaurant has to know about their customers before they can order. A person can’t just walk in and get some food if his or her name isn’t in the book yet.

When we’re hungry, we take the sensible approach and speak the restaurant’s language — they provide a menu and we order from it. This way the restaurant need only concern itself with the food they make, not the people who order it. That’s what I needed to do with the component—have the page tell it what to do, rather than vice versa.

Refactoring the code

I refactored the component so that the pages that used it spoke its language. Now the AccountView is concerned not with the pages that use it, but only with the elements it needs to draw.

adviceView.js

this.sideBar.show(new AccountView({
    showDeleteButton: false,
    showTargetBalance: true
}));

goalSetupView.js

this.sideBar.show(new AccountView({
    showDeleteButton: true,
    showTargetBalance: false
}));

Now, to use it on the rollover setup page we can simply add this code to show the AccountView:

rolloverSetupView.js

this.sideBar.show(new AccountView({
    showDeleteButton: true,
    showTargetBalance: false,
    showChangeButton: false
}));

Here is how we handle those options in the component with the new HTML:

new accountView.html

<div class="goal-name">
    <span class="name"><%= name() %></span>
    <span class="blue-pen"></span>

    <% if (showDeleteButton) { %>
        <span class="blue-x"></span>
    <% } else { %>
        <span class="status <%= account.status() %>"></span>
    <% } %>
</div>

<div class="goal-contents">
    <div class="row">
        <span>Type</span>
        <span><%= account.get('goalType') %></span>

        <% if (showChangeButton) { %>
            <button class="silver change-goal">Change</button>
        <% } %>
    </div>

    <% if (showTargetBalance) { %>
        <div class="row">
            <span>Target</span>
            <span class="goal-amount">
                <span><%= goalAmount() %></span>
                <span class="blue-pen"></span>
            </span>
        </div>
    <% } %>
</div>

While not substantially different, this new code is cleaner, and lets the AccountView deal only with what it needs to deal with. It should never need know what page it’s living on.

The Result

With this refactoring of the web code, I was able to re-design a component in a way that made it completely scalable—and also created a model to build new components. This is just one more way we incorporate efficiency into our platform—making it easier to put customers first.

Interested in engineering at Betterment? Betterment is an engineering-driven company that has developed the most-trusted online financial advisor based on the principles of optimization and efficiency. You can learn more about engineering jobs and our culture here.

Determination of most trusted online financial advisor reflects Betterment LLC’s distinction of having the most customers in the industry, made in reliance on customer counts, self-reported pursuant to SEC rules, across all online-only registered investment advisors.

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.

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.

Smart Saver and Other Savings Products: Our Recommendations

Smart Saver and Other Savings Products: Our Recommendations

We know from talking to Betterment customers that holding cash isn’t always intentional; it’s a choice by default—not knowing how, when, or why to put your money to work. We developed Smart Saver to help with that.

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.