Search code examples
model-view-controllerstoreember.jsseparation-of-concerns

EmberJS: Good separation of concerns for Models, Stores, Controllers, Views in a rather complex application?


I'm doing a fairly complex emberjs application, and tying it to a backend of APIs.

The API calls are not usually tied to any particular model, but may return objects of various types in different sections of the response, e.g. a call to Events API would return events, but also return media assets and individuals involved in those events.

I've just started with the project, and I'd like to get some expert guidance on how best to separate concerns to have a clean maintainable code base.

The way I am approaching this is:

  • Models: essentially handle records with their fields, and other computed properties. However, models are not responsible for making requests.
    • e.g. Individual, Event, Picture, Post etc.
  • Stores: They are essentially caches. For example, an eventStore would store all events received from the server so far (from possibly different requests) in an array, and also in an hash of events indexed by id.
    • e.g. individualStore, eventStore etc.
  • Controllers: They tie to a set of related API calls, e.g. eventsController would be responsible for fetching events or a particular event, or creating a new event etc. They would 'route' the response to different stores for later retrieval. They don't keep the response once it has been sent to stores.
    • e.g. eventsController, userSearchController etc.
  • Views: They are tied to a particular view. In general, my application may have several views at different places, e.g. latestEventsView on the Dashboard in addition to having a separate events page.
  • Templates: are what they are.

Quite often, my templates require to be bound directly to the stores (e.g. peopleView wants to list all the individuals in the individualStore in a list, sorted by some order).

And sometimes, they bind to a computed property

alivePeople: function () { ... }.property('App.individualStore.content.@each'),

The various filtering and sorting options 'chosen' in the view, should return different lists from the store. You can see my last question at what is the right emberjs way to switch between various filtering options?

Who should do this filtering, the view themselves or the stores?

Is this kind of binding across layers okay, or a code smell? Is the separation of concerns good, or am I missing something? Shouldn't controllers be doing something more here? Should my views directly bind to stores?

Any particular special case of MVC more suited to my needs?

Update 17 April 2012 My research goes on, particularly from http://vimeo.com/user7276077/videos and http://jzajpt.github.com/2012/01/17/emberjs-app-architecture.html and http://jzajpt.github.com/2012/01/24/emberjs-app-architecture-data.html

Some issues with my design that I've figured out are:

  • controllers making requests (stores or models or something else should do it, not controllers)
  • statecharts are missing -- they are important for view-controller interactions (after sometime you realize your interactions are no more simple)

This is a good example of state charts in action: https://github.com/DominikGuzei/ember-routing-statechart-example

UPDATE 9th JANUARY 2013

Yes, it's been long but this question is lately getting lots of views, and that's why I'd like to edit it so that people may get a sense.

Ember's landscape has changed a lot since this question was framed, and the new guides are much improved. EmberJS has come up with conventions (like Rails) and the MVC is much more well defined now.

Anybody still confused should read all the guides, and watch some videos: Seattle Ember.js Meetup

At the moment, I'm upgrading my application to Ember.js 1.0.0-pre2.


Solution

    • You should think of your application in terms of states. Have a look at this

    • Initially, only a route and a template are required to describe something and finally display it in the browser, that's what the new API of Emberjs tries to enforce. As your requirements get more elaborate you can throw in a view, a controller or an object. Each though answers a specific need.

    • Consider a view if you need to handle any browser events or wrap
      any 3rd party javascript lib you're using for animation, styling ..

    • Consider an Object if you need to capture domain specific
      information, most likely mimics backend information.

    • A controller is merely a proxy for the domain object and may encapsulate logic that doesn't pertain necessarily to the object.

    That's all what's to it. If you learn how to design your application in terms of states, the rest will fall into the right place, providing you're using the latest api, enforcing the rules i mentioned previously.