Services: A Rumination on Introducing a New Role into the Ember Programming Model

There’s lots of great discussion here, so thank you everyone.

Before replying to specific technical proposals, I’d like to address some of the responses that I think are caused by a fundamental misunderstanding of what Ember is after. Specifically:

  • Why even have an API for this? The underlying primitives make it easy to write my own services however I want.
  • Why create an Ember.Service base class? Just use Ember.Object.

To me and Yehuda, the notion of defining roles for objects is paramount in the Ember programming model.

If you’re pushing back against this feature, don’t ask yourself, “How hard is it to implement this simple feature with existing primitives?” Instead, ask yourself, “What can we, as a community, build over the next few years with the shared understanding of what a ‘service’ is?”

The point of creating new objects with new roles isn’t to add syntactic sugar on top of what we have today (though that is a nice benefit). The point is to get everyone developing Ember apps to use these objects to solve similar problems. That way, when someone has an insight into new ways that services can interact with the rest of the system, we have a foundation upon which we can reason about that interaction.

As you can see in this discussion, people have many different ideas about how services should work. If Ember shrugs its shoulders and says, “Just inject whatever you want,” our poor future API designer will be left with a mess on his or her hands.

A historical exemplar here is components. Take a look at @wycats’ first implementation of Ember.Component (then called Ember.Control): https://github.com/emberjs/ember.js/blob/ad4d1ef5fdda67c503c24346e097ddf06f77787f/packages/ember-views/lib/views/control.js.

The implementation is an embarrassingly small delta on top of the Ember.View primitive available on the time. Literally, components were just views that set their controller to themselves, and registered a Handlebars helper with the same name. That was it.

I remember at the time people pushing back, because it seemed like a small, trivial addition that would just cause confusion. “If you want to do this, you can do it in a few lines of code.”

But by giving a name—a role—to a new kind of object, as a community we were able to iterate on and expand the scope of that object, to the point where components are so much more than just “views whose controllers are themselves.” In fact, the implementation hasn’t changed that much. Instead, having components has given us a shared vocabulary to discuss the problem.

The router is another example of where we’re able to do awesome things because of the shared understanding of the roles of objects in the system. Things like query params are only possible because these roles are well-defined.

Services are the same. Don’t think about services in terms of “how hard would it be to implement this today?” Don’t think of it in terms of “I will lose the flexibility I need.” The container isn’t going away, and if services don’t do what you need, you can keep doing what you’re doing today.

Instead, think about how creating a vocabulary around the roles that services play in the system will allow us to have a discussion—and a shared implementation—that we can continue iterating on, as a community, for the years to come.

24 Likes