Michael Comella wrote on 11.04.2016 22:44:
Experience with these architectures on other platforms (e.g. MVC in web dev) would also be useful to hear! :)

I've been using strict MVC in XUL extensions and web apps. The way I use it is:

 * Model
   contains the logic, that is all abstract functionality. Most
   important rules are:
    1. model must never ever access the UI, under any circumstances.
       Decoupling happens via subject/observer design pattern or simple
       callbacks. E.g. all async model functions have a successCallback
       and errorCallback, which gets you a long way in decoupling.
       Callbacks should be prefered over generic observers, because
       they are more specific and more controllable and create less
       accidental cross-pollution.
    2. The model never initiates anything, all action is triggered by
       the UI. If there's some polling or push needed, then the UI
       requests it from the model and passes in a callback, the model
       is running the poll/push, and notifies the UI via callbacks.
    3. All code that can be cleanly put into the model (without
       violating rule 1 or 2) should be put there.
    4. I usually implement these as separate JavaScript files. It is
       easy to check that nothing in that files accesses the View or
       directly the Controller.
 * View
   contains the UI code. In XUL and web apps, that's XUL or HTML. It
   contains the structure of the windows.
     o Style is the looks, e.g. colors, margins, icons etc.. For web
       apps, that's in CSS - and style should not change the HTML, only
       CSS. In MVC, that's part of the View, but it's nice that HTML
       separates this.
 * Controller
   hooks up View with Model. In web apps, that's the JavaScript hooked
   up with the HTML. The controller
     o has the onload handlers that do the startup and and triggers the
       init of the app by calling the model init functions,
     o populates the View by calling the model,
     o it hooks up event handlers that call the appropriate model
       functions etc.
     o sets up poll/push listeners and hooks up their result to the UI.
 * Persistence
     o I usually implement persistence as part of the model, but
       encapsulated in library classes.
     o Persistence is often not a single method and thus a single
       layer, but storage happens several places: Sometimes files on
       disk, sometimes as preference, sometimes JSON, sometimes sqlite,
       sometimes on the server using REST+JSON calls.
     o I separate out the storage bits and bolts into a storage class,
       e.g. I have a high-level myPref class where I can just say
       myPref.get("bookmarks.autostore", false); or similar.


The above is my understand of the original MVC design, as defined by the GoF and others around that time. Since then, Microsoft and others have redefined it, and let the Controller or a Manager contain all the logic and the Model contains only data fields, no logic functions. However, my understanding of the OO idea is that objects contain both data and functions that operate on that data, this is why I chose the above approach of putting pure logic into the model.

A few other coding rules applying to all layers:

 *

   I try to make the code as dense as possible, that the code lines
   only show what I really try to accomplish and don't have a lot of
   technical bits and bolts.

 *

   Error handling

     o Exceptions and errorCalbacks
     o The function where the error appears first is responsible for
       creating a user-readable string for it. Other, higher-level
       functions only wrap it when they can add substantially important
       information for the end user.
     o Errors are generally passed up unchanged, up to a level that
       knows what to do with it. Either it can recover, then the error
       is handled on that layer where it can implement an alternative
       fallback. Or the error is shown to the user, then it's handled
       at the controller level which triggered the whole action. This
       allows me to have a different error UI depending on whether I'm
       in a main window (e.g. as error popup), dialog (e.g. error
       message shown inline), or in an automatic function (e.g. errors
       are startup not shown, but the feature is deactivated).


Example:

There might be an Account object that can read the username (and possibly password) from a preference, and has a function login(successCallback, errorCallback) that contacts a server. If the server accepted the credentials, successCallback is called, otherwise errorCallback(ex) with a specific reason (as error code and user-readable string) of why login failed. The Controller, on startup, checks with the Account object whether we have any stored credentials, and if so, asks to login() directly at startup. If it fails, it doesn't show an error, to not both the user, but we'll simply be logged out. It it succeeds, the successCallback that the Controller passed in then updates the UI to show the logged-in state. Or alternatively a generic "logged-in" observer that the Controller had hooked up between Model and View does that. If we're not logged in and the user clicks to log in, the Controller asks the View to show the login UI. The View returns the values, and the Controller passes them to Account and calls login() and updates the View. If now the errorCallback is called, then the Controller will call a View function to show the error. Or better yet, the login dialog shows the error inline.



_______________________________________________
mobile-firefox-dev mailing list
mobile-firefox-dev@mozilla.org
https://mail.mozilla.org/listinfo/mobile-firefox-dev

Reply via email to