Is there a layer missing in Ember 1.0?

In our Ember 0.9 app, we have the following:

  • models, which are in charge of data transport; some also have a bit of stateful logic that comes into play during their lifecycle
  • controllers, which coördinate collaboation among models; they have lots of logic about when to expire things, how to pass models around to various other controllers, and views, etc.
  • views, which express properties in a compound fashion (e.g. combining two properties from a controller or model into a new property), apply internationalization to properties from models and controllers, and handle events; some views also have a little bit of DOM expression in them (e.g. wrapping a property in a tag and inserting the result into an internationalization template)
  • templates, which combine view properties with complex DOM expressions

In 1.0, from what I understand,

  • models stay about the same
  • some of the logic we have in controllers moves to routes; some stays where it is
  • there is a deëmphasis on writing custom views; instead, what we now have in the view moves to controllers
  • templates stay about the same

But pushing things like “putting a property into a tag and inserting the result into an internationalization template” are very different from “applying save logic.” It seems weird to me to have both of those in the controller level.

So my question is: should there be another level? Perhaps a Presenter?

1 Like

I agree that the responsibilities of a Controller are somewhat blurry in Ember, especially since Router v2 (so, for 6 months or so). You suggest another layer called a Presenter, but I think the Controller, when used in that way, already approximates the job of a Presenter class, but, used in other ways, it has the more classical Controller responsibility of maintaining/managing application state, rather than just assembling the different data needed by the template to present the data.

It’s not clear to me whether developer ergonomics would improve/suffer if Ember distinguished between the two though… perhaps the somewhat loose definition of the Controller fills in some conceptual gaps that naturally arise in the dynamic environment of UI dev? Not to mention that it’s already challenging enough to keep in your brain that navigating to a route involves the assembly/generation of many different components: a Template, Controller, View, Route… and then possibly Presenter?

@ebryn has some thoughts as to whether Ember is missing a ViewController, which would have more direct access to the view object that it managed, among other things. Maybe this is relevant to the present discussion?

I shouldn’t have suggested only Presenter. I’m definitely open to other ideas like a BusinessRules UseCase layer behind the Controller (which then becomes more of a ViewController / Presenter).

A specific example might help. The following is in a View

userMast: function() {
  var userName = this.getPath('user.name'),
      emName = new Handlebars.SafeString('<em>%@</em>'.fmt(userName));
  return Em.I18n.t('user.mast', { name: emName });
}.property('user.name').cacheable()

And in a Controller:

save: function(event) {
  this.get('model').save()
    .then(function() {
      this.get('users').expire();
    }.bind(this))
    .then(function() {
      this.get('states').goToUsers();
    }.bind(this));
}

I don’t like the idea that those two pieces of code both end up in the same class.

Perhaps the answer is that much of what I’m calling Views are really now Components. Even though the UserMast isn’t reusable in any real sense, it does have semantic meaning and encapsulated behavior. I could see it being a Web Component in the future:

<section class='user'>
  <user-mast user="user" />
  <p>...</p>
</section>

I think that any application using MVC will need to build in application specific objects for it’s own business needs. I recently watched a good video http://www.youtube.com/watch?v=npOGOmkxuio (ruby conf: Baruco 2013: ‘Rules’, by @sandimetz) Which points out that inserting your own objects between the objects in your framework is a good way to extend functionality. A Presenter used by a controller is a good example, you could have other proxy objects or command objects to introduce specific behavior that your application needs. In general I think MVC is never completely enough to build a non-trivial application. In my opinion a Controller is enough from the framework, an app can inject objects into a controller to do more.

Yeah, I think component is conceptually the right abstraction. Even if it is not highly reusable a component can be “purpose built” for a specific task.

I feel like the composability is highly desirable feature of components.

In the above I could imagine a component that takes as part of its interface just a user “name” property and in another case take the whole “user” object like you have now.

This leaves the designer of a system to customize the layers of granularity. Components composed of other components holds a lot of conceptual utility for me personally.

Whenever I write code I am always striving to “forget about the outside world”. What lies beyond the curly braces of a function or object literal can just fade away. It feels easier to think about the internal implementation in a very limited scope and let the “interface” do all the semantic heavy lifting.

I am not sure what it is exactly but step up a layer or two to the controller and the router and it becomes very difficult for me to understand what is happening. With all the implicit behavior and reaching across concerns becomes almost too much cognitive overhead.

Components feel like they make ember easier to use as a framework. But that is just my personal bias.

THrowing in my agreement with @eccegordo. Here is a talk I gave about chopping up user interfaces into trees/heirarchies of components that only share the data they need to function.

I think there are shortcomings to the way Ember handles your folder structure WRT components atm but otherwise I think they are exactly the correct abstraction. This opinion is confirmed/supported by react.js which is components all the way down (for better or worse).