| <h1>MVC Architecture</h1> |
| |
| |
| <p> |
| As modern browsers become more powerful with rich features, |
| building full-blown web applications in JavaScript is not only feasible, |
| but increasingly popular. |
| Based on |
| <a href="http://httparchive.org/trends.php?s=intersection&minlabel=Jan+20+2011&maxlabel=Jan+15+2012">trends</a> |
| on <a href="http://httparchive.org/">HTTP Archive</a>, |
| deployed JavaScript code size has grown 45% over the course of the year. |
| </p> |
| |
| <img src="{{static}}/images/jstransferrequests.png" |
| width="568" |
| height="292" |
| alt="JS transfer size and JS requests"> |
| |
| <p> |
| With JavaScript's popularity climbing, |
| our client-side applications are much more complex than before. |
| Application development requires collaboration from multiple developers. |
| Writing <strong>maintainable</strong> and |
| <strong>reusable</strong> code is crucial in the new web app era. |
| The Chrome packaged app, with its rich client-side features, is no exception. |
| </p> |
| |
| <p> |
| Design patterns are important to write maintainable and reusable code. |
| A pattern is a reusable solution that can be applied to commonly occurring problems in software design — |
| in our case — writing Chrome packaged apps. |
| We recommend that developers decouple the app |
| into a series of independent components following the MVC pattern. |
| </p> |
| |
| <p> |
| In the last few years, |
| a series of JavaScript MVC frameworks have been developed, |
| such as <a href="http://backbonejs.org/">backbone.js</a>, <a href="http://emberjs.com/">ember.js</a>, <a href="http://angularjs.org/">AngularJS</a>, <a href="http://sencha.com/">Sencha</a>, <a href="http://kendo.com/">Kendo UI</a>, and more. |
| While they all have their unique advantages, each one of them follows some form of MVC pattern |
| with the goal of encouraging developers to write more structured JavaScript code. |
| </p> |
| |
| <h2 id="mvc">MVC pattern overview</h2> |
| |
| <p> |
| MVC offers architectural benefits over standard JavaScript — |
| it helps you write better organized, and therefore more maintainable code. |
| This pattern has been used and extensively tested |
| over multiple languages and generations of programmers. |
| </p> |
| |
| <p> |
| MVC is composed of three components: |
| </p> |
| |
| <img src="{{static}}/images/mvc.png" |
| width="466" |
| height="303" |
| alt="model-view-controller"> |
| |
| <h3>Model</h3> |
| |
| <p> |
| Model is where the application’s data objects are stored. |
| The model doesn’t know anything about views and controllers. |
| When a model changes, typically it will notify its observers that a change has occurred. |
| </p> |
| |
| <p> |
| To understand this further, let’s use the Todo list app, a simple, one page web app that tracks your task list. |
| </p> |
| |
| <br> |
| |
| <img src="{{static}}/images/todos.png" |
| width="444" |
| height="366" |
| alt="model-view-controller"> |
| |
| <p> |
| The model here represents attributes associated |
| with each todo item such as description and status. |
| When a new todo item is created, |
| it is stored in an instance of the model. |
| </p> |
| |
| <h3>View</h3> |
| |
| <p> |
| View is what's presented to the users and how users interact with the app. |
| The view is made with HTML, CSS, JavaScript and often templates. |
| This part of your Chrome packaged app has access to the DOM. |
| </p> |
| |
| <p> |
| For example, in the above todo list web app, |
| you can create a view that nicely presents the list of todo items to your users. |
| Users can also enter a new todo item through some input format; |
| however, the view doesn’t know how to update the model because that’s the controller’s job. |
| </p> |
| |
| <h3>Controller</h3> |
| |
| <p> |
| The controller is the decision maker and the glue between the model and view. |
| The controller updates the view when the model changes. |
| It also adds event listeners to the view and |
| updates the model when the user manipulates the view. |
| </p> |
| |
| <p> |
| In the todo list web app, |
| when the user checks an item as completed, |
| the click is forwarded to the controller. |
| The controller modifies the model to mark item as completed. |
| If the data needs to be persistent, it also makes an async save to the server. |
| In rich client-side web app development such as Chrome packaged apps, |
| keeping the data persistent in local storage is also crucial. |
| In this case, the controller also handles saving the data |
| to the client-side storage such as <a href="app_storage.html">FileSystem API</a>. |
| </p> |
| |
| <p> |
| There are a few variations of the MVC design pattern |
| such as MVP (Model–View–Presenter) |
| and MVVP(Model–View–ViewModel). |
| Even with the so called MVC design pattern itself, |
| there is some variation between the traditional MVC pattern |
| vs the modern interpretation in various programming languages. |
| For example, some MVC–based frameworks will have |
| the view observe the changes in the models |
| while others will let the controller handle the view update. |
| This article is not focused on the comparison of various implementations |
| but rather on the separation–of–concerns and |
| it's importance in writing modern web apps. |
| </p> |
| |
| <p> |
| If you are interested in learning more, |
| we recommend <a href="https://plus.google.com/u/0/115133653231679625609/posts">Addy Osmani's</a> online book: <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">Learning JavaScript Design Patterns</a>. |
| </p> |
| |
| <p> |
| To summarize, the MVC pattern brings modularity |
| to application developers and it enables: |
| </p> |
| |
| <ul> |
| <li>Reusable and extendable code.</li> |
| <li>Separation of view logic from business logic.</li> |
| <li>Allow simultaneous work between developers who are responsible |
| for different components (such as UI layer and core logic).</li> |
| <li>Easier to maintain.</li> |
| </ul> |
| |
| <h2 id="mvcpersistence">MVC persistence patterns</h2> |
| |
| <p> |
| There are many different ways of implementing persistence |
| with an MVC framework, each with different trade–offs. |
| When writing Chrome packaged apps, |
| choose the frameworks with MVC and persistence patterns |
| that feel natural to you and fit you application needs. |
| </p> |
| |
| <h3>Model does its own persistence - ActiveRecord pattern</h3> |
| |
| <p> |
| Popular in both server–side frameworks like Ruby on Rails, |
| and client-side frameworks like |
| <a href="http://backbonejs.org">Backbone.js</a> and |
| <a href="http://emberjs.com/">ember.js</a>, |
| the ActiveRecord pattern places the responsibility |
| for persistence on the model itself |
| and is typically implemented via JSON API. |
| </p> |
| |
| <p> |
| A slightly different take from |
| having a model handle the persistence |
| is to introduce a separate concept of Store and Adapter API. |
| Store, Model and |
| Adapter (in some frameworks it is called Proxy) |
| work hand by hand. |
| Store is the repository that holds the loaded models, |
| and it also provides functions such as creating, |
| querying and filtering the model instances contained within it. |
| </p> |
| |
| <p> |
| An adapter, or a proxy, receives the requests from a store and |
| translates them into appropriate actions to take |
| against your persistent data layer |
| (such as JSON API). |
| This is interesting in the modern web app design |
| because you often interact with more than one persistent data layer |
| such as a remote server and browser’s local storage. |
| Chrome package apps provides both |
| <a href="storage.html">Chrome Storage API</a> and |
| <a href="fileSystem.html">HTML 5 fileSystem API</a> for client side storage. |
| </p> |
| |
| <p>Pros:</p> |
| |
| <ul> |
| <li>Simple to use and understand.</li> |
| </ul> |
| |
| <p> |
| Cons: |
| </p> |
| |
| <ul> |
| <li>Hard to test since the persistence layer is ‘baked’ into the object hierarchy.</li> |
| <li>Having different objects use different persistent stores is difficult |
| (for example, FileSystem APIs vs indexedDB vs server–side).</li> |
| <li>Reusing Model in other applications may create conflicts, |
| such as sharing a single Customer class between two different views, |
| each view wanting to save to different places.</li> |
| </ul> |
| |
| <h3>Controller does persistence</h3> |
| |
| <p> |
| In this pattern, the controller holds a reference |
| to both the model and a datastore |
| and is responsible for keeping the model persisted. |
| The controller responds to lifecycle events like Load, Save, Delete, |
| and issues commands to the datastore to fetch or update the model. |
| </p> |
| |
| <p> |
| Pros: |
| </p> |
| |
| <ul> |
| <li>Easier to test, controller can be passed a mock datastore to write tests against.</li> |
| <li>The same model can be reused with multiple datastores just by constructing controllers with different datastores.</li> |
| </ul> |
| |
| <p> |
| Cons: |
| </p> |
| |
| <ul> |
| <li>Code can be more complex to maintain.</li> |
| </ul> |
| |
| <h3>AppController does persistence</h3> |
| |
| <p> |
| In some patterns, there is a supervising controller responsible |
| for navigating between one MVC and another. |
| The AppController decides, for example, |
| that a ‘Back’ button moves the client from an editing screen |
| (which contains MVC widgets/formats), |
| to a settings screen. |
| </p> |
| |
| <p> |
| In the AppController pattern, |
| the AppController responds to events |
| and changes the app’s current screen by issuing a call |
| to the datastore to load any models needed and |
| constructing all of the matching views and controllers for that screen. |
| </p> |
| |
| <p> |
| Pros: |
| </p> |
| |
| <ul> |
| <li>Moves persistence layer even higher up the stack where it can be easily changed.</li> |
| <li>Doesn’t pollute lower level controllers like a DatePickerController with the need to know about persistence.</li> |
| <li>Aligns nicely with an ‘Intent’ model. |
| Each AppController corresponds to an intent, like “ChoosePhoto”, or “SendMessage”. |
| The Intent contains a reference to the model data needed (Customer#123) and |
| the type of CRUD operation (load, save, delete, and so on).</li> |
| </ul> |
| |
| <p> |
| Cons: |
| </p> |
| |
| <ul> |
| <li>Each ‘Page/Screen’ of the app now requires a lot of boilerplate to write or update: Model, View, Controller, AppController.</li> |
| </ul> |
| |
| <h3>Recommended MVC frameworks</h3> |
| |
| <p> |
| MVC is crucial to designing Chrome packaged apps. |
| We recommend the following <a href="app_csp.html">CSP–Compliant</a> MVC frameworks |
| for writing secure and scalable Chrome packaged apps: |
| </p> |
| |
| <ul> |
| <li><a href="http://angularjs.org/">AngularJS</a> |
| (<a href="https://github.com/GoogleChrome/textdrive-app">Text Drive Reference App</a>)</li> |
| <li><a href="http://kendo.com/">Kendo UI</a> |
| (<a href="https://github.com/GoogleChrome/kendo-photo-booth-app">Photo Booth Reference App</a>)</li> |
| <li><a href="http://www.sencha.com/">Sencha</a> |
| (<a href="https://github.com/GoogleChrome/sencha-video-player-app">Video Player Reference App</a>)</li> |
| </ul> |
| |
| <h2 id="resources">Useful resources</h2> |
| |
| <h3>Online</h3> |
| |
| <ul> |
| <li><a href="http://www.html5rocks.com/">HTML5Rocks.com</a></li> |
| <li><a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">Learning JavaScript Design Patterns</a> |
| (by Addy Osmani)</li> |
| <li><a href="http://addyosmani.github.com/todomvc/">TodoMVC</a></li> |
| </ul> |
| |
| <h3>Books</h3> |
| |
| <ul> |
| <li><a href="http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X">JavaScript Web Applications</a> |
| (By Alex MacCaw)</li> |
| <li><a href="http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752/ref=pd_sim_b_2">JavaScript Patterns</a> |
| (By Stoyan Stefonov)</li> |
| <li><a href="http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680">Maintainable JavaScript</a> |
| (By Nicolas Z. Zakas)</li> |
| </ul> |
| |
| <p class="backtotop"><a href="#top">Back to top</a></p> |