So, why use it? We get asked this a lot. Many folks have pinged us on Twitter:
Deciding on a team’s stack comes down to what the team simply likes and the nature of the requirements the team must fulfill. This demands experimentation: we try one thing for a development cycle and decide based on sprint outcomes. No amount of product matrices, cost-benefit analyses, and “Top 10” listicles can outweigh the value of testing a technology stack with something as nebulous as team dynamics. For us, Ember.js fit well with our philosophy, work styles, and cadence.
Requirements, both technical and political
Requirements are more tangible, and Ember.js made sense for what we needed in the first weeks of our team’s infancy as well as where we were after one year of maturity. These requirements were and continue to be of both a technical and political nature: we needed to build many apps quickly, respond to rapidly evolving customer needs, and organize our source code in a manner friendly to a growing team. We also needed to demonstrate the viability of open source software and agile methodology to ship better products faster and more cheaply.
Additionally, many of these products had already existed in some form or another. They already had large, opinionated, and demographically disparate user bases that depended on them every day. City agencies are faced with this challenge regularly because they don’t just have a single niche market with an explicit bottom line. This means we did not need to prioritize things like customer conversion rates or first meaningful paint metrics. Instead, our bottom line was much more qualitative and couched within a human-centered design framework. We needed something flexible enough to get us to production, and Ember.js fit the bill.
“Just answer the question, sir.”
We chose Ember.js for a few reasons:
- High productivity out of the box
- Convention over configuration
- Vibrant addon ecosystem
Now, to go beyond the mere talking points:
High productivity out of the box
What does this really mean? Every week, every time we demoed the sprint outcome to the whole agency, we — including the customers themselves — learned more nuances and contours of the project’s requirements. When that happened, we did not want to think about installing a routing library to preserve query parameters. We did not want to configure a command-line tool to build Sass files. We did not want to architect a custom data persistence layer. As important as those things are, we could not afford to agonize over the esoteric details of the boilerplate. We needed to finish the product, prove its value to customers, and optimize later.
Convention over configuration
Working at a breakneck pace over the past year was not sustainable. It helped us fulfill our political requirements, but it harmed the long-term maintainability of the tools we created. That said, Ember.js enforced necessary structural constraints throughout our source code to ensure organization across our apps. This helped us avoid panicked spaghetti code scenarios, preserved a lot of our past work for later reuse (within reason), and made it easy to jump across projects as needed.
There were tradeoffs, naturally — an opinionated framework means less snowflake configuration that may be more performant in some niche context. To borrow a quote from the Rails doctrine:
…the power of convention isn’t without peril. When Rails makes it so trivial to do so much, it is easy to think every aspect of an application can be formed by precut templates. But most applications worth building have some elements that are unique in some way. It may only be 5% or 1%, but it’s there.
The hard part is knowing when to stray from convention. When are the deviating particulars grave enough to warrant an excursion? I contend that most impulses to be a beautiful and unique snowflake are ill considered, and that the cost of going off the Rails is under appreciated, but just enough of them won’t be that you need to examine all of them carefully.
Being a team specialized in making lots and lots of map-based web applications, we certainly did run into situations where we needed to stray away from the conventions or perceived “best practices” to accommodate our needs. This was perfectly acceptable because we met our needs one way or another, we provided new feedback to the community, and we expanded the number of use cases for a framework flexible enough to fulfill them.
There is no “right way” to build an Ember app. You are not “doing it wrong” if you want to use GraphQL or Redux or MobX or TypeScript or Flow or Mocha just because that’s not what comes out of the box. No one but you knows whether a particular tool will make you and your team more productive.
Our team established a balance between honoring the conventions of the framework and configuring it as we saw fit.
Vibrant addon ecosystem
Addons aren’t by any means unique to Ember.js — it was easy enough to find bindings addons for certain libraries we wanted to use. However, the ability to consume addon code from within a project, and overwrite the addon’s methods and properties through the Ember Object model meant we could use anything the community produced without worrying about feeling “locked-in” to its API or spending time forking the entire source to make minor changes. As easily as we could repurpose the community’s code for project requirements, we could just as easily contribute back. This was by design.
Further, after finishing our fourth Ember.js app, we realized how much code we could share across our applications. We were able to battle-test internal APIs, take those lessons, and preserve them in addons. This gave us labs-ui and ember-mapbox-composer, two addons we use to hasten our development cycle.
We don’t just use Ember.js
The “right tool for the job” is a helpful mantra here, and it helps keep us honest about deciding our stack. For example, our homepage is built with a React-based project called Gatsby, and our geocoder documentation site — as well as a few other small tools — are also built with React. In fact, the whole team has built production projects in Backbone, React, Rails, Sinatra, and Django, and has learned a tremendous amount from all of them in the process.
In spite of their use, we aren’t the faithful acolytes of Ember.js or any one developer mantra. Tom Dale talks a lot about these:
…the downside of a mantra is that the original context around why it was created gets lost. They tend to take on a sort of religious feel. I’ve seen in-depth technical discussions get derailed because people would invoke the mantra as an axiom rather than as having being derived from first principles.
I think that applies here, too — in spite of their usefulness, we also can’t allow creativity to be stifled by said mantras or even small-team platitudes. If someone has an idea and they want to use jQuery, D3.js, or Vue.js to demonstrate their idea, I think that’s a great thing.
Shoulders of Giants
So there you have it: a few good reasons why we chose to use Ember.js to deliver six (out of eight) critical products in under a year’s time. That said, technology is only successful when it grows and adapts to the changing terrain of its environment. We chose a framework that allowed us to see and use the best of the Web and anything else just on the horizon. Perhaps, in the years ahead, we may find a better solution that works for us and our constituents. But by then at least we will have been afloat long enough at all to have that conversation.
At one point, Uber’s engineering team used the open source database PostgreSQL to build an app that moved people around cities. They probably did not build their own database software in the first week. Instead, I imagine, they opted for the shoulders of giants before becoming one themselves.