Pancake/Front End Architecture

From MozillaWiki
Jump to: navigation, search

Discussion

WidgetBridge

The WidgetBridge model has a certain amount of overlap with the data model that backs a given view. The difference is that WidgetBridge gives us another criteria by which to display a view (not necessarily tied to data). I'm not sure if this is useful yet. It's like a ViewModel (concerned with display), whereas the model that backs the view is a pretty much a Model2-type model (concerned with data), but the view has access to it.

Should we let collection-backed views be list views and model-backed views be single views, and make the presence of a model in a collection the canonical definition of whether that view displays? If that's the case, we should make AppView a collection-backed view, right? Not quite. WidgetBridge is a keyed collection, where items in it have names. This means we can easily identify specific widgets -- regardless of their actual value -- and place them into areas, rather than just listing them.

So maybe we should create a KeyedCollection instead? It would have the same API as a collection, but allow named models. But there is another differences: we're storing views, not models, because widgets are concerned with presentation. Maybe this is the right solution for templating widgets after all.

But does it make sense to use the same paradigm for flat-list views, since we already have the code? Is that over-abstraction?

View Types

The headache of keeping the widget registry up-to-date based on data model events is a bummer. It really only works if the widget bridge is used exclusively as a viewmodel for views that don't have data backing them.

Lets try solving this view issue by re-thinking how views are organized; we need 3 different kinds of views:

  • WidgetView: named widgets (views) that get mapped to specific areas in the DOM. We could even dispense with named keys altogether and use the DOM selector as the key. Backed by a viewmodel (which looks basically like the WidgetBridge model we have now).
  • ListView: backed by a collection, this view lists subviews in order, based on collection data. You can set the sub-view constructor.
  • View (Backbone.View): just a plain 'ol view.

This maps nicely to typical data structures:

  • Keyed Object (WidgetView)
  • Ordered Array (ListView)
  • Single Data Point (View)

What should this look like in practice?

Asymmetrical DOM handling

This issue applies whether or not we use WidgetBridge. Given the current configuration, where views know their models, but models have no knowledge of views, we end up with asymmetrical DOM handling. Typically, the control flow for a list view looks like this.

   Add model to collection
     -> Fire collection "add" event
       -> List View: create single view for model, append to DOM
   
   Remove model from collection
     -> Fire collection and model "remove" event
       -> Single View: remove self from DOM

I'm not sure that this is a problem, but it means trusting the single views to clean up after themselves.

We could have references between view and model be bi-directional, but this poses other problems: since many models can potentially share one view, models would need an array of views and need to know which view to remove. So the view would need to know about the collection it belongs to, since model instances can belong to many collections... eeew.

Edit: WidgetBridge does mitigate this issue somewhat. widget:remove and widget:register events provide good hooks for manipulating the DOM inside of a list view.

Edit 2: Never mind, it doesn't WidgetBridge only mitigates this issue when the addition/removal happens for ViewModel-related reasons (e.g. "I no longer want to display this widget here"). If a model is removed from a collection (data reasons), the view for that model still needs to know how to clean up after itself. Does this mean that we also need to remove the widget from the registry? Probably. I see this as a sign that we need to use the ViewModel only as a ViewModel (for views that don't have any data except display data) and let the data be the canonical representation of what needs to be displayed for data-backed views.

Framework Investigation

Spoiler: we went with Backbone. It does just enough of what we need, and not much more.

Addy Osmani is writing a mini-book on Backbone on Github: https://github.com/addyosmani/backbone-fundamentals

High-level doc on Pancake architecture https://pancake.etherpad.mozilla.org/22

App MVC / Router

Investigating URL router options. Related to https://bugzilla.mozilla.org/show_bug.cgi?id=707281.

We want our solution to use pushState and be as simple as possible.

Seems like all of these could be thinner. What about regex-based matching, so we're not converting between formats?

Backbone.js seems like a good option:

  • Gives us
    • history.pushstate() URL routing
    • Object extension (mix prototypes to do inheritance)
    • Functional helpers through _.js
    • Models, Views, Controllers
    • Events on objects
    • Zepto compatible
    • Proxied/pluggable io (Backbone.sync)
  • Backbone + Underscore weighs 26k minified, 8k gzipped. Zepto + Backbone + Underscore together weigh 45k minified, or 15k minified and gzipped. That + require should be all the glue we need for our app. jQuery alone is 92k, 32k gzipped.

We should be able to create widgets by amalgamating Backbone.Model, Backbone.View, Backbone.Controller, this seems like a good strategy, using the same MVC for the app and widgets. Update: it looks like this is the case. Backbone doesn't seem to care too much how you use it.

Cherry-pick from a framework?

Widgets/Views

Notes on interface widgets in ui-component branch. Related to https://bugzilla.mozilla.org/show_bug.cgi?id=707279.

Widgets have their own MVC sub-structure:

    App
  /  |  \
 M   V   C
          \
         Bridge
           |
         Widget
         /  |  \
       M    V   C

Resources:

In Backbone, Views are a combination of Controller/View/Template. This means we will need to create a way for views to contain views.

  • AppView
    • Register Widget method
    • App Template
    • AppModel reference
    • Widget Model collection
    • Widget View collection
      • WidgetView
        • WidgetModel reference
        • Widget Template

Persistence/Models/Sync