Choosing Ember over React in 2016 – Two-Factor Everything

  • The post is about why, when Clef was deciding whether to use React or Ember to build Instant 2FA, we went with Ember.
  • Ember F astBoot enables server side rendering in any Ember app with one command.
  • Because of the way Ember enforces conventions, these addons almost always work out of the box.
  • One of the goals of Ember is to give the developer the best experience currently available without having them do any work (or as little as possible) .
  • We haven’t had to do (2) but it seems much simpler in Ember with Ember addons.

One month ago, we started working on a new product: Instant 2FA, the easiest way to add two-factor authentication to any site in less than an hour. Currently, whether you roll your own two-factor…

@jessepollak: Just wrote about choosing @emberjs over @reactjs for building @Instant2FA. Lucky to have so many good options!

One month ago, we started working on a new product: Instant 2FA, the easiest way to add two-factor authentication to any site in less than an hour.

Currently, whether you roll your own two-factor with Google Authenticator or use an API service like Authy, a standard integration often takes weeks.

With Instant 2FA, we’re building a solution that reduces the entire integration to 3 API calls and provides everything out of the box: Google Authenticator, SMS, and Yubikey support; remember this computer; rate-limiting and alerting; and with our first few customers, we’ve done the integration in a development environment in less than an hour.

This blog post outlines our thinking behind choosing Ember (a technology none of us had ever used before) over React (which we’ve been running for 2.5 years in production at Clef) and our reflections on the decision after one month of work.

Every new project requires a million technology decisions. Luckily, 4 years of company experience building Clef, a two-factor product used by nearly a million websites, made most of our decisions obvious. We knew our backend services would be built with Python, SQL, and Flask, leveraging all the tooling and libraries we’d spent years working on. 

The frontend, however, was a different story: we’ve been using React and flux (powered by reflux) in production for two and a half years, but as we began considering how to build Instant 2FA, we wondered whether using a more fully featuredframework like Ember or Angular would be a better decision.

When we started considering Ember over React, there were two main hypotheses that drove our curiosity:

As we dug into each of these hypotheses, we found compelling evidence that ultimately led us to choosing Ember for both our applications.

One of the best things about React is that, since it’s only a view layer, it can easily be added to a pre-existing JavaScript application. Three years ago, when the frontend for Clef was built on our own object oriented JavaScript framework and we started exploring whether React could help us, this was one of the best parts. Rather than swap in a new “framework,” we gradually replaced different components with React components — adding additional logic layers on top of React (like redux to handle data flow) only as necessary. 

 Over time, this gradual composition of libraries cemented into our own little incarnation of the React ecosystem. Different libraries duplicated each other, but things worked. We used:

A few months ago, we did a little side project where we had to create a client application from scratch. We went with React for the view layer, but given the dramatic evolution of the surrounding ecosystem over the last few years, we ended up with a very different composition:

It was fun to get to pick and choose, but every step of the way we doubted our choices: were we making the wrong decision with a given library choice? We were “configuring” our own framework from the tools available in the React ecosystem, but had major concerns about whether our configuration would help or hurt us.

Entrusting high-level architectural technology decisions to engineers who have limited experience in a domain often leads to bikeshedding and bad decisions — and this showed in the side project we did. We are a team of 4 engineers building Clef, but since we regularly maintain code across 5 platforms (iOS, Android, backend Python, client JavaScript, and our WordPress plugin), only two of our engineers have really worked on our React application. By the end of working on the side project as a team, we’d saddled ourselves with a set of tools which often proved unstable and got in the way of getting our work done.

With Instant 2FA, every engineer would be working in JavaScript for half their time, so this meant more than half of the people writing code would be relatively inexperienced JavaScript engineers. This makeup — senior overall, but relatively inexperienced with front end engineering — the issue of convention over configuration felt particularly relevant.

As we started working on Instant 2FA, the thought of Ember making all these decisions for us — enforcing a convention over configuration — was very alluring. Some of the decisions we were most excited about not making were:

Ember ships with testing built in and tests are auto-generated when new units (models, routes, services, serializers, etc) are created. For the last React application we built, we’d spent days setting up test harnesses, acceptance tests, and all of the other tools necessary to have a fast, easy-to-use test suite, and we still were constantly frustrated with our setup. Ember built acceptance and unit testing into the framework, which we hoped would make it easier for our code to be tested at every level.

). This toolchain comes with sane defaults out of the box (ES6 and modules, for instance), but the community built around this standard is the most powerful part.

In our previous setups, every time we needed to change our build to implement a specific goal, we needed to write custom code. One great example of this is uploading sourcemaps to Sentry when our code is deployed. In our React apps, we did this in a shell script after our webpack build was done.

, almost any new step we need to add is available as an Ember addon (like ember-cli-deploy-sentry). And, because of the way Ember enforces conventions, these addons almost always work out of the box. As a result our build and deploy logic has transformed from a mess of custom JavaScript and shell script logic to a clean composition of different community maintained modules.

there were established patterns for how to do things — even if some of those patterns felt a little outdated.

Ember FastBoot enables server side rendering in any Ember app with one command. Having explored server side rendering in our previous React apps, we knew that for every configuration of libraries around React there was an equally complicated server side rendering setup. Server side rendering wasn’t something we needed out of the box, and we still haven’t enabled it, but knowing that it’s a cli command away, rather than a major project away, is a weight off our shoulders.

After outlining and exploring all the decisions we would need to make if we went with the React ecosystem, taking those decisions out of our hands, and putting them in the hands of a core team and community that has been building client-side applications for years, became an obvious choice.

When the topic of progressive enhancement is discussed, it most often refers to the progressive enhancement of webpages from plain HTML & CSS to advanced, interactive JavaScript powered applications. The argument goes like this: for people browsing a web application, their experience should be progressively enhanced given the technologies their browser supports (or has enabled). A user with no JS support in their browser will get a plain HTML & CSS experience — which though it may be slower or clunkier, will still work — while a user with a modern browser will be served the JavaScript necessary to make their experience fully modern. In other words, with progressive enhancement, we meet users where they are — and, perhaps most importantly, they get the best experience available to them without having to do any work.

The best ideas of progressive enhancement should be evident in JavaScript frameworks and libraries as well — we refer to this a Progressive Developer Experience (Progressive DX) and it’s one of the defining goals of the Ember framework and community.

. For each new iteration of progress at the conceptual level, a new library or tool needs to be added to your toolset: or tying this back to the language of progressive enhancement, the developer has to do work or change their tools to get the best experience.

In contrast, one of the goals of Ember is to give the developer the best experience currently available without having them do any work (or as little as possible). Take the same example of uni-directional data flow. While Ember 1.0 existed before this pattern became well known, as the concept grew in popularity and conceptual clarity in the React & flux ecosystem the Ember core team started figuring out how they could roll it back into Ember. With Ember 2.0, and the gradual shift from controllers to components, uni-directional data flow has found a home in Ember without Ember developers needing to add new libraries or adopt major conceptual paradigms. It may have taken a little longer to get to this enhancement — but when it came it was well thought out, built into the framework they already used, and there was a straightforward migration path. This is a perfect example of how Ember employs Progressive DX to give its developers access to the latest patterns and tools!

Reading the core team’s work during our evaluation period, this theme of Progressive DX felt consistent: features like Ember Fastboot (server side rendering), glimmer (faster rendering enginer), routable components (uni-directional data flow), and services (isolated cross cutting concerns) are all examples of how the Ember experience has been progressively enhanced, often borrowing directly from patterns other frameworks have introduced, to give Ember users the best of the web.

At the beginning of a project that will last for years, it’s comforting to know that we have a team working to integrate the latest and greatest into the tools we already use, so we don’t have to search for it ourselves.

One month in, we’re very happy with our decision to use Ember. It’s still early, but overall, our two hypotheses have held — we’re enjoying following conventions defined by more senior engineers and are already benefiting from different ways Ember has progressively enhanced our experience.

Ember is sweet. Really easy to pick up enough to design well, and I really love using css-modules.

We’ve also found a ton of other, smaller reasons to love Ember.

command. After working with the framework for a little more than a month, it’s one of our favorite things: having a canonical way to generate any unit of logic (model, route, service, etc), means there’s no cognitive overhead to writing many, small, easily testable units. It also means that whenever a unit is created, a test is auto-generated for it, so developers have an even easier time testing their code.

, it’s even easy to generate complex relationship setups, which has historically been a challenge in our development workflows.

template in every template folder. When data is loading, or loading fails, Ember will automatically render the respective loading or error template closest to the route the user is currently on. This lets you easily add a top-level loading state, then add specific loading states throughout your app where necessary. It’s beautiful!

Of course everything hasn’t been perfect — learning any new framework is a challenge and migrating from one framework to another always brings some amount of frustration with the different paradigms.

Hot-reloading and time travel debugging are two of the most useful tools that have come out of the React ecosystem. 

 With hot-reloading, when you change code, the logic is reloaded in place, without requiring a page load. As a developer, this means you don’t need to navigate back to the point in the page — with the appropriate state — where you were working every time you make a change. Instead, the logic just refreshes and you can keep on working. 

 With time travel debugging, it’s trivial to see how state in your application changes over time, and jump through those different states. This makes it easy to diagnose and fix bugs that come from complicated state manipulation!

 Not having access to these tools is sad, but not the end of the world.

In our React applications, styling components was always a point of frustration. This boiled down to two primary issues:

In the Ember eco-system, (1) seems similarly unsolved: we’ve gone with css-modules for styling components, but have had to do contortions to make it work with a base styling system (like foundation). We haven’t had to do (2) yet, but it seems much simpler in Ember with Ember addons.

This post isn’t about whether Ember is better than React. This post is about why, when Clef was deciding whether to use React or Ember to build Instant 2FA, we went with Ember.

There are an infinite number of ways to build a web application and there are an infinite number of reasons the right decisions for our needs could be the wrong ones for you. This diversity of options is what makes the web evolve so fast — and what makes it so powerful. 

We hope you learned something from our thought process — and we’d love to learn something from yours. If you’ve made the same choice, we’d love to hear why! If you’ve made a different one, we’d love to hear why too!

Choosing Ember over React in 2016 – Two-Factor Everything