blob: 5c829f3cbd9f639911cb7fc133fdb1a917629503 [file] [log] [blame]
<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 &mdash;
in our case &mdash; 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 &mdash;
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&ndash;View&ndash;Presenter)
and MVVP(Model&ndash;View&ndash;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&ndash;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&ndash;of&ndash;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&ndash;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&ndash;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&ndash;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&ndash;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>