Interested in working with us? We are hiring!

See open positions

Rollup: What we have learned from sharing UI code at AdRoll

Mars Jullian Written by Mars Jullian, November 19, 2015

This is the third post in a series of three blog posts about Rollup, AdRoll’s UI component library. This post covers what we learned from building a UI component library. For details on why we built the UI component library see the first post in the series and for how we built it see the second post.

At end of Rollup component and developer tool development, we reflected on what we did and realized that we had learned four important lessons from the work:

Let’s dig into each one separately.

Making reusable components for app developers is hard

When we first started working on Rollup, we wanted to make sure that individual components would be easy to use for any developer on any team. For app developers, we wanted them to be able to use Rollup components even if:

To address the first three points, each published component has a CDN build. The CDN build, among other things, contains transpiled code. The transpiled JS means that other teams do not need to have a fancy build tool to use a component in their project and that app developers do not need to use JSX in order to add the components to their application.

Not only does this mean that components can be used in projects not built in React, but also makes it easier to use for those who are new to JavaScript. The CDN build accomplishes this by allowing them to use whichever framework they feel most comfortable with (e.g. jQuery or plain JavaScript).

To allow app developers to use the same version of a component forever, components are published to npm according to SemVer and the CDN assets are pushed to S3 under a versioned URL. Other applications using npm can leverage npm’s dependency management to use the same version forever. While other app developers loading components via the CDN can always load the same version through the versioned URL.

We also want app developers to be able to use the components even if we had not thought about their use case. We can accomplish this in two ways. The first way is to provide well defined and general interfaces for the components (see interfaces are hard for more details).

The second way we want to accomplish is through open communication channels. Even if interfaces are well-defined and general, we want to be able to customize and iterate on them quickly. In order to accomplish this we have created a Slack channel, #frontend_helpdesk, dedicated to frontend and Rollup help. We track all bugs and feature requests received there using GitHub issues.

By keeping the lines of communications open and judiciously tracking feature requests and bug fixes, we aim to quickly address new use cases. The issue tracking allows us to track and implement the needed fixes ourselves, and serves as a place where we can foster further conversation on how to support a new use case.

Making reusable components for contributors is hard

The developer tools we put in place surrounding the components aim to make it easier to contribute to the component library. The goal of the tooling was to enable Rollup contributors to:

Focus on the important things when developing a component

To develop and publish a new component, contributors should not have to worry about boilerplate like build configuration and file structure. To that end, we built a Rollup component generator using Yeoman. The generator takes the name of the component and then creates all files needed for a blank component. After running the generator, contributors can just hit the ground running.

Each component has an examples/ directory and a Gulp task for watching the changes made to the component and reloading the example in the browser. This makes it easy for contributors to test the functionality that they are working on in an isolated development and removes the hassle of having to set up a test application to interact with the component.

Focus on the important things when reviewing a component

We also want reviewers of pull requests in the Rollup repo to be able to focus on the important things when looking over someone else’s work. To that end, we have set up a global linter and Jest tests. The linting and test suite are automatically run on every single PR by Jenkins. The reviewer no longer needs to remember to do these checks, since it is done for them.

Instead, the reviewer can focus on the code quality and changes to component interfaces. In addition and thanks to each component’s examples/ directory, reviewers can also interact with the component and verify functionality, just like the component’s author(s) can.

Interfaces are hard

When starting work on Rollup and trying to use these components in other applications, we quickly realized that it mattered how easy it was to integrate a component. Enter the interface. Here are some of the best practices we learned while building them:

The first point hopes to limit the pain for app developers integrating components into their applications.

The second and third points together form the essence of what we learned when designing component interfaces. The idea behind these two points is to encourage contributors to limit the number of React props each component needs to be minimally functional, but be careful to define each prop in such a way that also supports more complicated use cases at the same time.

To help explain what we mean by that, let’s take a look at the columns prop for our data table component:

columns: [{
    key: String
    label: String
    accessor: Function
    render: Function
    textAlignment: (TEXT_ALIGN_LEFT|TEXT_ALIGN_RIGHT)
    widthMultiplier: Number
    adminOnly: Boolean
}, ...]

Let’s take a look at the accessor and render attributes that each column can have. In addition to the columns prop, the table also expects an array of data. The accessor in the columns prop is a function, that when given a data item will return a value that is then fed to the render function for that same column.

Together, the accessor and render support the simple use case of simply displaying information for a given data item without the data table component having to know the internal organization of each item.

However, because the accessor and render attributes are functions, they also support more complicated use cases. For example, these two attributes on a given column can be used to render line charts that summarize data for a particular data item. To do that, the accessor could return an array of data points, while the render can return anything as long as React can render it. Allowing the app developer using the component to return JSX or a React element for the line chart. For example:

Rollup Data Table complicated use case

In the above example, the accessor and render functions are general enough to support straightforward uses of the data table and more complicated ones as well.

Making everything look the same is hard

Making things look the same across products and components developed in isolation is not an easy feat. For example, the blue used in the date picker needs to be the same blue that’s used in our data table. As another example, the top navbar needs to be pixel perfect across products, so that the end user feels like they are navigating within the same application, even if that’s not how the product is implemented.

To solve this problem, we came up with a Rollup component that maintains styles shared by applications and components. This component is called ar-style-base, and all common styles are built into it:

Even though the base styles can be overridden, they provide a good starting point for new components and products that need to share colors, typography, and iconography.

So what’s next?

We continue to encourage the adoption of our components at AdRoll and share the things we have learned. Not only will sharing internally the things we’ve learned help grow our contributor pool, but it will also help grow the frontend expertise of the company as a whole.

As we mentioned at the end of the first blog post in this series, we decided to build our own components since we were not happy with open-source solutions. So, the next big thing we have in mind for Rollup is to open source them one at a time.

Thanks for reading this series and we hope you have enjoyed what we have to share about Rollup!

See open positions AdRoll on Github