/backbone-fundamentals.db
Unknown | 10016 lines | 9502 code | 514 blank | 0 comment | 0 complexity | 3c9a05535dd9097fd5fcc98f1a7284f4 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?xml version="1.0" encoding="utf-8" ?>
- <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
- "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
- <article>
- <articleinfo>
- <title></title>
- </articleinfo>
- <sect1 id="prelude">
- <title>Prelude</title>
- <para>
- Welcome to my (in-progress) book about the
- <ulink url="http://documentcloud.github.com/backbone/">Backbone.js</ulink>
- framework for structuring JavaScript applications. It’s released
- under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0
- Unported
- <ulink url="http://creativecommons.org/licenses/by-nc-sa/3.0/">license</ulink>
- meaning you can both grab a copy of the book for free or help to
- further
- <ulink url="https://github.com/addyosmani/backbone-fundamentals/">improve</ulink>
- it.
- </para>
- <para>
- I’m very pleased to announce that this book will be out in physical
- form in a few months time via
- <ulink url="http://oreilly.com">O’Reilly Media</ulink>. Readers will
- have the option of purchasing the latest version in either print or
- a number of digital formats then or can grab a recent version from
- this repository.
- </para>
- <para>
- Corrections to existing material are always welcome and I hope that
- together we can provide the community with an up-to-date resource
- that is of help. My extended thanks go out to
- <ulink url="https://github.com/jashkenas">Jeremy Ashkenas</ulink>
- for creating Backbone.js and
- <ulink url="https://github.com/addyosmani/backbone-fundamentals/contributors">these</ulink>
- members of the community for their assistance tweaking this project.
- </para>
- <para>
- I hope you find this book helpful!
- </para>
- </sect1>
- <sect1 id="table-of-contents">
- <title>Table Of Contents</title>
- <itemizedlist>
- <listitem>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <link linkend="mvc-mvp">MVC, MVP & Backbone.js</link>
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <link linkend="models">Models</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="views">Views</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="collections">Collections</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="routers">Routers</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="namespacing">Namespacing</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="additional-tips">Additional tips</link>
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <link linkend="restful">Building RESTful applications with
- Backbone</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="stack1">Building Backbone apps with Node.js,
- Express, Mongoose and MongoDB</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="stack2">Building Backbone apps with Ruby,
- Sinatra, Haml and MongoDB</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="pagination">Paginating Backbone.js Requests
- & Collections</link>
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <link linkend="modularjs">Modular JavaScript</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="organizingmodules">Organizing modules with
- RequireJS and AMD</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="externaltemplates">Keeping your templates
- external with the RequireJS text plugin</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="optimizingrequirejs">Optimizing Backbone apps
- for production with the RequireJS Optimizer</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="practicalrequirejs">Practical: Building a
- modular Backbone app with AMD & RequireJS</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="decouplingbackbone">Decoupling Backbone with
- the Mediator and Facade patterns</link>
- </para>
- </listitem>
- <listitem>
- <para>
- Backbone & jQuery Mobile
- </para>
- </listitem>
- <listitem>
- <para>
- Practical: Building A Modular Mobile App With Backbone &
- jQuery Mobile
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <link linkend="unittestingjasmine">Unit Testing Backbone
- Applications With Jasmine</link>
- </para>
- </listitem>
- <listitem>
- <para>
- Introduction
- </para>
- </listitem>
- <listitem>
- <para>
- Jasmine
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Suites, Specs And Spies
- </para>
- </listitem>
- <listitem>
- <para>
- TDD With Backbone
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="testing-jasmine-models">Testing
- Models</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="testing-jasmine-collections">Testing
- Collections</link>
- </para>
- </listitem>
- <listitem>
- <para>
- <link linkend="testing-jasmine-views">Testing
- Views</link>
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- <link linkend="unittestingqunit">Unit Testing Backbone
- Applications With QUnit And SinonJS</link>
- </para>
- </listitem>
- <listitem>
- <para>
- Introduction
- </para>
- </listitem>
- <listitem>
- <para>
- QUnit
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Assertions
- </para>
- </listitem>
- <listitem>
- <para>
- Adding structure to assertions
- </para>
- </listitem>
- <listitem>
- <para>
- Assertion examples
- </para>
- </listitem>
- <listitem>
- <para>
- Fixtures
- </para>
- </listitem>
- <listitem>
- <para>
- Asynchronous code
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- SinonJS
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Stubs
- </para>
- </listitem>
- <listitem>
- <para>
- Mocks
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- Practical
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Testing Models
- </para>
- </listitem>
- <listitem>
- <para>
- Testing Collections
- </para>
- </listitem>
- <listitem>
- <para>
- Testing Views
- </para>
- </listitem>
- <listitem>
- <para>
- Testing Events
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- </listitem>
- </itemizedlist>
- </sect1>
- <sect1 id="introduction">
- <title><a name="introduction">Introduction</a></title>
- <para>
- As JavaScript developers, we are at an interesting point in time
- where not only do we have mature solutions to help organize the
- JavaScript powering our applications based on a separation of
- concerns, but developers looking to build non-trivial projects are
- almost spoiled for choice for frameworks that can help structure
- their applications.
- </para>
- <para>
- Maturity in software (framework) development isn’t simply about how
- long a framework has been around. It’s about how solid the framework
- is and more importantly how well it’s evolved to fill its role. Has
- it become more effective at solving common problems? Does it
- continue to improve as developers build larger and more complex
- applications with it?
- </para>
- <para>
- In this book, I will be covering the popular Backbone.js, which I
- consider the best of the current family of JavaScript architectural
- frameworks.
- </para>
- <para>
- Topics will include MVC theory and how to build applications using
- Backbone’s models, views, collections and routers. I’ll also be
- taking you through advanced topics like modular development with
- Backbone.js and AMD (via RequireJS), how to build applications using
- modern software stacks (like Node and Express), how to solve the
- routing problems with Backbone and jQuery Mobile, tips about
- scaffolding tools, and a lot more.
- </para>
- <para>
- If this is your first time looking at Backbone.js and you’re still
- unsure whether or not to give it a try, why not take a look at how
- <ulink url="http://github.com/addyosmani/todomvc">a Todo
- application</ulink> can be implemented in Backbone and several other
- popular Javascript frameworks before reading further?
- </para>
- <para>
- The goal of this book is to create an authoritative and centralized
- repository of information that can help those developing real-world
- apps with Backbone. If you come across a section or topic which you
- think could be improved or expanded on, please feel free to submit a
- pull-request. It won’t take long and you’ll be helping other
- developers avoid problems you’ve run into before.
- </para>
- </sect1>
- <sect1 id="fundamentals">
- <title><a name="fundamentals">Fundamentals</a></title>
- <para>
- In this section we are going to cover the context into which a
- framework like Backbone.js fits. Let’s begin our journey into
- understanding Backbone better with a look at code architecture.
- </para>
- <sect2 id="mvc-mvp-backbone.js">
- <title><a name="mvc-mvp">MVC, MVP & Backbone.js</a></title>
- <para>
- Before exploring any JavaScript frameworks that assist in
- structuring applications, it can be useful to gain a basic
- understanding of architectural design patterns. Design patterns
- are proven solutions to common development problems and can
- suggest structural approaches to help guide developers in adding
- some organization to their applications.
- </para>
- <para>
- Patterns are useful because they’re a set of practices that build
- upon the collective experience of skilled developers who have
- repeatedly solved similar problems. Although developers 10 or 20
- years ago may not have been using the same programming languages
- when implementing patterns in their projects, there are many
- lessons we can learn from their efforts.
- </para>
- <para>
- In this section, we’re going to review two popular patterns - MVC
- and MVP. We’ll be exploring in greater detail how Backbone.js
- implements these patterns shortly to better appreciate where it
- fits in.
- </para>
- </sect2>
- </sect1>
- <sect1 id="mvc">
- <title>MVC</title>
- <para>
- MVC (Model-View-Controller) is an architectural design pattern that
- encourages improved application organization through a separation of
- concerns. It enforces the isolation of business data (Models) from
- user interfaces (Views), with a third component (Controllers)
- traditionally present to manage logic, user-input and the
- coordination of models and views. The pattern was originally
- designed by
- <ulink url="http://en.wikipedia.org/wiki/Trygve_Reenskaug">Trygve
- Reenskaug</ulink> while working on Smalltalk-80 (1979), where it was
- initially called Model-View-Controller-Editor. MVC was described in
- depth in
- <ulink url="http://www.amazon.co.uk/Design-patterns-elements-reusable-object-oriented/dp/0201633612"><quote>Design
- Patterns: Elements of Reusable Object-Oriented
- Software</quote></ulink> (The <quote>GoF</quote> or <quote>Gang of
- Four</quote> book) in 1994, which played a role in popularizing its
- use.
- </para>
- <sect2 id="smalltalk-80-mvc">
- <title>Smalltalk-80 MVC</title>
- <para>
- It’s important to understand what the original MVC pattern was
- aiming to solve as it has changed quite heavily since the days of
- its origin. Back in the 70’s, graphical user-interfaces were far
- and few between. An approach known as
- <ulink url="http://martinfowler.com/eaaDev/uiArchs.html">Separated
- Presentation</ulink> began to be used as a means to make a clear
- division between domain objects which modeled concepts in the real
- world (e.g a photo, a person) and the presentation objects which
- were rendered to the user’s screen.
- </para>
- <para>
- The Smalltalk-80 implementation of MVC took this concept further
- and had an objective of separating out the application logic from
- the user interface. The idea was that decoupling these parts of
- the application would also allow the reuse of models for other
- interfaces in the application. There are some interesting points
- worth noting about Smalltalk-80’s MVC architecture:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- A Domain element was known as a Model and were ignorant of the
- user-interface (Views and Controllers)
- </para>
- </listitem>
- <listitem>
- <para>
- Presentation was taken care of by the View and the Controller,
- but there wasn’t just a single view and controller. A
- View-Controller pair was required for each element being
- displayed on the screen and so there was no true separation
- between them
- </para>
- </listitem>
- <listitem>
- <para>
- The Controller’s role in this pair was handling user input
- (such as key-presses and click events), doing something
- sensible with them.
- </para>
- </listitem>
- <listitem>
- <para>
- The Observer pattern was relied upon for updating the View
- whenever the Model changed
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Developers are sometimes surprised when they learn that the
- Observer pattern (nowadays commonly implemented as a
- Publish/Subscribe system) was included as a part of MVC’s
- architecture decades ago. In Smalltalk-80’s MVC, the View and
- Controller both observe the Model: anytime the Model changes, the
- Views react. A simple example of this is an application backed by
- stock market data - for the application to show real-time
- information, any change to the data in its Models should result in
- the View being refreshed instantly.
- </para>
- <para>
- Martin Fowler has done an excellent job of writing about the
- <ulink url="http://martinfowler.com/eaaDev/uiArchs.html">origins</ulink>
- of MVC over the years and if you are interested in further
- historical information about Smalltalk-80’s MVC, I recommend
- reading his work.
- </para>
- </sect2>
- </sect1>
- <sect1 id="mvc-as-we-know-it">
- <title>MVC As We Know It</title>
- <para>
- We’ve reviewed the 70’s, but let us now return to the here and now.
- The MVC pattern has been applied to a diverse range of programming
- languages. For example, the popular Ruby on Rails is an
- implementation of a web application framework based on MVC for the
- Ruby language. JavaScript now has a number of MVC frameworks,
- including Ember.js, JavaScriptMVC, and of course Backbone.js. Given
- the importance of avoiding <quote>spaghetti</quote> code, a term
- which describes code that is very difficult to read or maintain due
- to its lack of structure, let’s look at what the MVC pattern enables
- the Javascript developer to do.
- </para>
- <para>
- MVC is composed of three core components:
- </para>
- <sect2 id="models">
- <title>Models</title>
- <para>
- Models manage the data for an application. They are concerned with
- neither the user-interface nor presentation layers, but instead
- represent structured data that an application may require. When a
- model changes (e.g when it is updated), it will typically notify
- its observers (e.g views, a concept we will cover shortly) that a
- change has occurred so that they may react accordingly.
- </para>
- <para>
- To understand models better, let us imagine we have a JavaScript
- photo gallery application. In a photo gallery, a photo would merit
- its own model, as it represents a unique kind of domain-specific
- data. The Photo model may represent attributes such as a caption,
- image source and additional meta-data. A specific photo would be
- stored in an instance of a model. Here’s an example of a simple
- Photo model implemented with Backbone.js:
- </para>
- <programlisting language="javascript">
- var Photo = Backbone.Model.extend({
- // Default attributes for the photo
- defaults: {
- // Ensure that each photo created has an `src`.
- src: "placeholder.jpg",
- caption: "A default image",
- viewed: false
- },
- initialize: function() {
- }
- });
- </programlisting>
- <para>
- The built-in capabilities of models vary across frameworks,
- however it’s common for them to support validation of attributes,
- where attributes represent the properties of the model, such as a
- model identifier. When using models in real-world applications we
- generally also need a way of persisting models. Persistence allows
- us to edit and update models with the knowledge that their most
- recent states will be saved somewhere, for example in a web
- browser’s localStorage data-store or synchronized with a database.
- </para>
- <para>
- A model may also have multiple views observing it. Imagine our
- Photo model contained meta-data such as the longitude and latitude
- where the photo was taken, a list of people present in the photo,
- and a list of tags. A developer could create a single view that
- displayed all these attributes, or might create three separate
- views to display each attribute. The important detail is that the
- Photo model doesn’t care how these views are organized, it simply
- announces updates to its data as necessary. We’ll come back to
- Views in more detail later.
- </para>
- <para>
- It is not uncommon for modern MVC/MV* frameworks to provide a
- means to group models together. In Backbone, these groups are
- called <quote>Collections</quote>. Managing models in groups
- allows us to write application logic based on notifications from
- the group, should any model it contains change. This avoids the
- need to manually observe individual model instances.
- </para>
- <para>
- Here’s how we might group Photo models into a simplified Backbone
- Collection:
- </para>
- <programlisting language="javascript">
- var PhotoGallery = Backbone.Collection.extend({
- // Reference to this collection's model.
- model: Photo,
- // Filter down the list of all photos that have been viewed
- viewed: function() {
- return this.filter(function(photo){ return photo.get('viewed'); });
- },
- // Filter down the list to only photos that have not yet been viewed
- unviewed: function() {
- return this.without.apply(this, this.viewed());
- }
- });
- </programlisting>
- <para>
- If you read older texts on MVC, you may come across a description
- of models as also managing application <quote>state</quote>. In
- JavaScript applications <quote>state</quote> has a specific
- meaning, typically referring to the current <quote>state</quote>
- of a view or sub-view on a user’s screen at a fixed time. State is
- a topic which is regularly discussed when looking at Single-page
- applications, where the concept of state needs to be simulated.
- </para>
- </sect2>
- <sect2 id="views">
- <title>Views</title>
- <para>
- Views are a visual representation of models that present a
- filtered view of their current state. A view typically observes a
- model and is notified when the model changes, allowing the view to
- update itself accordingly. Design pattern literature commonly
- refers to views as <quote>dumb</quote>, given that their knowledge
- of models and controllers in an application is limited.
- </para>
- <para>
- Users interact with views, which usually means reading and editing
- model data. For example, in our photo gallery application example,
- model viewing might happen in a user interface with a big image, a
- caption, and a list of tags. Model editing could be done through
- an <quote>edit</quote> view where a user who has selected a
- specific photo could edit its caption, tags, or other metadata in
- a form.
- </para>
- <para>
- In MVC, the actual task of updating the Model falls to
- Controllers, which we’ll be covering shortly.
- </para>
- <para>
- Let’s explore Views a little further using a simple JavaScript
- example. Below we can see a function that creates a single Photo
- view, consuming both a model instance and a controller instance.
- </para>
- <para>
- We define a <literal>render()</literal> utility within our view
- which is responsible for rendering the contents of the
- <literal>photoModel</literal> using a JavaScript templating engine
- (Underscore templating) and updating the contents of our view,
- referenced by <literal>photoEl</literal>.
- </para>
- <para>
- The <literal>photoModel</literal> then adds our
- <literal>render()</literal> callback as one of its subscribers, so
- that through the Observer pattern it can trigger the view to
- update when the model changes.
- </para>
- <para>
- You may wonder where user interaction comes into play here. When
- users click on any elements within the view, it’s not the view’s
- responsibility to know what to do next. A Controller makes this
- decision. In our sample implementation, this is achieved by adding
- an event listener to <literal>photoEl</literal> which will
- delegate handling the click behavior back to the controller,
- passing the model information along with it in case it’s needed.
- </para>
- <para>
- The benefit of this architecture is that each component plays its
- own separate role in making the application function as needed.
- </para>
- <programlisting language="javascript">
- var buildPhotoView = function( photoModel, photoController ){
- var base = document.createElement('div'),
- photoEl = document.createElement('div');
- base.appendChild(photoEl);
- var render= function(){
- // We use a templating library such as Underscore
- // templating which generates the HTML for our
- // photo entry
- photoEl.innerHTML = _.template('photoTemplate', {src: photoModel.getSrc()});
- }
- photoModel.addSubscriber( render );
- photoEl.addEventListener('click', function(){
- photoController.handleEvent('click', photoModel );
- });
- var show = function(){
- photoEl.style.display = '';
- }
- var hide = function(){
- photoEl.style.display = 'none';
- }
- return{
- showView: show,
- hideView: hide
- }
- }
- </programlisting>
- <para>
- <emphasis role="strong">Templating</emphasis>
- </para>
- <para>
- In the context of JavaScript frameworks that support MVC/MV*, it
- is worth looking more closely at JavaScript templating and its
- relationship to Views.
- </para>
- <para>
- It has long been considered bad practice (and computationally
- expensive) to manually create large blocks of HTML markup
- in-memory through string concatenation. Developers using this
- technique often find themselves iterating through their data,
- wrapping it in nested divs and using outdated techniques such as
- <literal>document.write</literal> to inject the
- <quote>template</quote> into the DOM. This approach often means
- keeping scripted markup inline with standard markup, which can
- quickly become difficult to read and maintain, especially when
- building large applications.
- </para>
- <para>
- JavaScript templating libraries (such as Handlebars.js or
- Mustache) are often used to define templates for views as HTML
- markup containing template variables. These template blocks can be
- either stored externally or within script tags with a custom type
- (e.g <quote>text/template</quote>). Variables are deliminated
- using a variable syntax (e.g {{name}}). Javascript template
- libraries typically accept data in JSON, and the grunt work of
- populating templates with data is taken care of by the framework
- itself. This has a several benefits, particularly when opting to
- store templates externally as this can let applications load
- templates dynamically on an as-needed basis.
- </para>
- <para>
- Let’s compare two examples of HTML templates. One is implemented
- using the popular Handlebars.js library, and the other uses
- Underscore’s <quote>microtemplates</quote>.
- </para>
- <para>
- <emphasis role="strong">Handlebars.js:</emphasis>
- </para>
- <programlisting language="html">
- <li class="photo">
- <h2>{{caption}}</h2>
- <img class="source" src="{{src}}"/>
- <div class="meta-data">
- {{metadata}}
- </div>
- </li>
- </programlisting>
- <para>
- <emphasis role="strong">Underscore.js Microtemplates:</emphasis>
- </para>
- <programlisting language="html">
- <li class="photo">
- <h2><%= caption %></h2>
- <img class="source" src="<%= src %>"/>
- <div class="meta-data">
- <%= metadata %>
- </div>
- </li>
- </programlisting>
- <para>
- You may also use double curly brackets (i.e
- <literal>{{}}</literal>) (or any other tag you feel comfortable
- with) in Microtemplates. In the case of curly brackets, this can
- be done by setting the Underscore
- <literal>templateSettings</literal> attribute as follows:
- </para>
- <programlisting language="javascript">
- _.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };
- </programlisting>
- <para>
- <emphasis role="strong">A note on navigation and state</emphasis>
- </para>
- <para>
- It is also worth noting that in classical web development,
- navigating between independent views required the use of a page
- refresh. In single-page JavaScript applications, however, once
- data is fetched from a server via Ajax, it can be dynamically
- rendered in a new view within the same page. Since this doesn’t
- automatically update the URL, the role of navigation thus falls to
- a <quote>router</quote>, which assists in managing application
- state (e.g allowing users to bookmark a particular view they have
- navigated to). As routers are however neither a part of MVC nor
- present in every MVC-like framework, I will not be going into them
- in greater detail in this section.
- </para>
- </sect2>
- <sect2 id="controllers">
- <title>Controllers</title>
- <para>
- Controllers are an intermediary between models and views which are
- classically responsible for two tasks: they both update the view
- when the model changes and update the model when the user
- manipulates the view.
- </para>
- <para>
- In our photo gallery application, a controller would be
- responsible for handling changes the user made to the edit view
- for a particular photo, updating a specific photo model when a
- user has finished editing.
- </para>
- <para>
- It’s with controllers that most JavaScript MVC frameworks depart
- from this interpretation of the MVC pattern. The reasons for this
- vary, but in my opinion, Javascript framework authors likely
- initially looked at server-side interpretations of MVC (such as
- Ruby on Rails), realized that that approach didn’t translate 1:1
- on the client-side, and so re-interpreted the C in MVC to solve
- their state management problem. This was a clever approach, but it
- can make it hard for developers coming to MVC for the first time
- to understand both the classical MVC pattern and the
- <quote>proper</quote> role of controllers in other non-Javascript
- frameworks.
- </para>
- <para>
- So does Backbone.js have Controllers? Not really. Backbone’s Views
- typically contain <quote>controller</quote> logic, and Routers
- (discussed below) are used to help manage application state, but
- neither are true Controllers according to classical MVC.
- </para>
- <para>
- In this respect, contrary to what might be mentioned in the
- official documentation or in blog posts, Backbone is neither a
- truly MVC/MVP nor MVVM framework. It’s in fact better to see it a
- member of the MV* family which approaches architecture in its own
- way. There is of course nothing wrong with this, but it is
- important to distinguish between classical MVC and MV* should you
- be relying on discussions of MVC to help with your Backbone
- projects.
- </para>
- </sect2>
- <sect2 id="controllers-in-spine.js-vs-backbone.js">
- <title>Controllers in Spine.js vs Backbone.js</title>
- <para>
- <emphasis role="strong">Spine.js</emphasis>
- </para>
- <para>
- We now know that controllers are traditionally responsible for
- updating the view when the model changes (and similarly the model
- when the user updates the view). Since Backbone doesn’t have its
- <emphasis role="strong">own</emphasis> explicit controllers, it’s
- useful to review the controller from another MVC framework to
- appreciate the difference in implementations. Let’s take a look at
- <ulink url="http://spinejs.com/">Spine.js</ulink>:
- </para>
- <para>
- In this example, we’re going to have a controller called
- <literal>PhotosController</literal> which will be in charge of
- individual photos in the application. It will ensure that when the
- view updates (e.g a user edited the photo meta-data) the
- corresponding model does too.
- </para>
- <para>
- (Note: We won’t be delving heavily into Spine.js beyond this
- example, but it’s worth looking at it to learn more about
- Javascript frameworks in general.)
- </para>
- <programlisting language="javascript">
- // Controllers in Spine are created by inheriting from Spine.Controller
- var PhotosController = Spine.Controller.sub({
- init: function(){
- this.item.bind("update", this.proxy(this.render));
- this.item.bind("destroy", this.proxy(this.remove));
- },
- render: function(){
- // Handle templating
- this.replace($("#photoTemplate").tmpl(this.item));
- return this;
- },
- remove: function(){
- this.el.remove();
- this.release();
- }
- });
- </programlisting>
- <para>
- In Spine, controllers are considered the glue for an application,
- adding and responding to DOM events, rendering templates and
- ensuring that views and models are kept in sync (which makes sense
- in the context of what we know to be a controller).
- </para>
- <para>
- What we’re doing in the above example is setting up listeners in
- the <literal>update</literal> and <literal>destroy</literal>
- events using <literal>render()</literal> and
- <literal>remove()</literal>. When a photo entry gets updated, we
- re-render the view to reflect the changes to the meta-data.
- Similarly, if the photo gets deleted from the gallery, we remove
- it from the view. In case you were wondering about the
- <literal>tmpl()</literal> function in the code snippet: in the
- <literal>render()</literal> function, we’re using this to render a
- JavaScript template called #photoTemplate which simply returns a
- HTML string used to replace the controller’s current element.
- </para>
- <para>
- What this provides us with is a very lightweight, simple way to
- manage changes between the model and the view.
- </para>
- <para>
- <emphasis role="strong">Backbone.js</emphasis>
- </para>
- <para>
- Later on in this section we’re going to revisit the differences
- between Backbone and traditional MVC, but for now let’s focus on
- controllers.
- </para>
- <para>
- In Backbone, controller logic is shared between Backbone.View and
- Backbone.Router. Earlier releases of Backbone contained something
- called Backbone.Controller, but it was renamed to Router to
- clarify its role.
- </para>
- <para>
- A Router’s main purpose is to translate URL requests into
- application states. When a user browses to the URL
- www.example.com/photos/42, a Router could be used to show the
- photo with that ID, and to define what application behavior should
- be run in response to that request. Routers
- <emphasis>can</emphasis> contain traditional controller
- responsibilities, such as binding the events between models and
- views, or rendering parts of the page. However, Backbone
- contributor Tim Branyen has pointed out that it’s possible to get
- away without needing Backbone.Router at all for this, so a way to
- think about it using the Router paradigm is probably:
- </para>
- <programlisting language="javascript">
- var PhotoRouter = Backbone.Router.extend({
- routes: { "photos/:id": "route" },
- route: function(id) {
- var item = photoCollection.get(id);
- var view = new PhotoView({ model: item });
- something.html( view.render().el );
- }
- }):
- </programlisting>
- </sect2>
- </sect1>
- <sect1 id="what-does-mvc-give-us">
- <title>What does MVC give us?</title>
- <para>
- To summarize, the separation of concerns in MVC facilitates
- modularization of an application’s functionality and enables:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Easier overall maintenance. When updates need to be made to the
- application it is clear whether the changes are data-centric,
- meaning changes to models and possibly controllers, or merely
- visual, meaning changes to views.<literallayout></literallayout>
- </para>
- </listitem>
- <listitem>
- <para>
- Decoupling models and views means that it’s straight-forward to
- write unit tests for business
- logic<literallayout></literallayout>
- </para>
- </listitem>
- <listitem>
- <para>
- Duplication of low-level model and controller code is eliminated
- across the application
- </para>
- </listitem>
- <listitem>
- <para>
- Depending on the size of the application and separation of
- roles, this modularity allows developers responsible for core
- logic and developers working on the user-interfaces to work
- simultaneously
- </para>
- </listitem>
- </itemizedlist>
- <sect2 id="delving-deeper">
- <title>Delving deeper</title>
- <para>
- Right now, you likely have a basic understanding of what the MVC
- pattern provides, but for the curious, we’ll explore it a little
- further.
- </para>
- <para>
- The GoF (Gang of Four) do not refer to MVC as a design pattern,
- but rather consider it a <quote>set of classes to build a user
- interface</quote>. In their view, it’s actually a variation of
- three other classical design patterns: the Observer (Pub/Sub),
- Strategy and Composite patterns. Depending on how MVC has been
- implemented in a framework, it may also use the Factory and
- Decorator patterns. I’ve covered some of these patterns in my
- other free book, JavaScript Design Patterns For Beginners if you
- would like to read into them further.
- </para>
- <para>
- As we’ve discussed, models represent application data, while views
- handle what the user is presented on screen. As such, MVC relies
- on Pub/Sub for some of its core communication (something that
- surprisingly isn’t covered in many articles about the MVC
- pattern). When a model is changed it <quote>publishes</quote> to
- the rest of the application that it has been updated. The
- <quote>subscriber</quote>–generally a Controller–then updates the
- view accordingly. The observer-viewer nature of this relationship
- is what facilitates multiple views being attached to the same
- model.
- </para>
- <para>
- For developers interested in knowing more about the decoupled
- nature of MVC (once again, depending on the implementation), one
- of the goals of the pattern is to help define one-to-many
- relationships between a topic and its observers. When a topic
- changes, its observers are updated. Views and controllers have a
- slightly different relationship. Controllers facilitate views to
- respond to different user input and are an example of the Strategy
- pattern.
- </para>
- </sect2>
- <sect2 id="summary">
- <title>Summary</title>
- <para>
- Having reviewed the classical MVC pattern, your should now
- understand how it allows developers to cleanly separate concerns
- in an application. You should also now appreciate how JavaScript
- MVC frameworks may differ in their interpretation of MVC, and how
- they share some of the fundamental concepts of the original
- pattern.
- </para>
- <para>
- When reviewing a new JavaScript MVC/MV* framework, remember - it
- can be useful to step back and consider how it’s opted to approach
- Models, Views, Controllers or other alternatives, as this can
- better help you grok how the framework expects to be used.
- </para>
- </sect2>
- </sect1>
- <sect1 id="mvp">
- <title>MVP</title>
- <para>
- Model-view-presenter (MVP) is a derivative of the MVC design pattern
- which focuses on improving presentation logic. It originated at a
- company named
- <ulink url="http://en.wikipedia.org/wiki/Taligent">Taligent</ulink>
- in the early 1990s while they were working on a model for a C++
- CommonPoint environment. Whilst both MVC and MVP target the
- separation of concerns across multiple components, there are some
- fundamental differences between them.
- </para>
- <para>
- For the purposes of this summary we will focus on the version of MVP
- most suitable for web-based architectures.
- </para>
- <sect2 id="models-views-presenters">
- <title>Models, Views & Presenters</title>
- <para>
- The P in MVP stands for presenter. It’s a component which contains
- the user-interface business logic for the view. Unlike MVC,
- invocations from the view are delegated to the presenter, which
- are decoupled from the view and instead talk to it through an
- interface. This allows for all kinds of useful things such as
- being able to mock views in unit tests.
- </para>
- <para>
- The most common implementation of MVP is one which uses a Passive
- View (a view which is for all intents and purposes
- <quote>dumb</quote>), containing little to no logic. MVP models
- are almost identical to MVC models and handle application data.
- The presenter acts as a mediator which talks to both the view and
- model, however both of these are isolated from each other. They
- effectively bind models to views, a responsibility held by
- Controllers in MVC. Presenters are at the heart of the MVP pattern
- and as you can guess, incorporate the presentation logic behind
- views.
- </para>
- <para>
- Solicited by a view, presenters perform any work to do with user
- requests and pass data back to them. In this respect, they
- retrieve data, manipulate it and determine how the data should be
- displayed in the view. In some implementations, the presenter also
- interacts with a service layer to persist data (models). Models
- may trigger events but it’s the presenter’s role to subscribe to
- them so that it can update the view. In this passive architecture,
- we have no concept of direct data binding. Views expose setters
- which presenters can use to set data.
- </para>
- <para>
- The benefit of this change from MVC is that it increases the
- testability of your application and provides a more clean
- separation between the view and the model. This isn’t however
- without its costs as the lack of data binding support in the
- pattern can often mean having to take care of this task
- separately.
- </para>
- <para>
- Although a common implementation of a
- <ulink url="http://martinfowler.com/eaaDev/PassiveScreen.html">Passive
- View</ulink> is for the view to implement an interface, there are
- variations on it, including the use of events which can decouple
- the View from the Presenter a little more. As we don’t have the
- interface construct in JavaScript, we’re using it more as more a
- protocol than an explicit interface here. It’s technically still
- an API and it’s probably fair for us to refer to it as an
- interface from that perspective.
- </para>
- <para>
- There is also a
- <ulink url="http://martinfowler.com/eaaDev/SupervisingPresenter.html">Supervising
- Controller</ulink> variation of MVP, which is closer to the MVC
- and
- <ulink url="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</ulink>
- patterns as it provides data-binding from the Model directly from
- the View. Key-value observing (KVO) plugins (such as Derick
- Bailey’s Backbone.ModelBinding plugin) introduce this idea of a
- Supervising Controller to Backbone.
- </para>
- </sect2>
- </sect1>
- <sect1 id="mvp-or-mvc">
- <title>MVP or MVC?</title>
- <para>
- MVP is generally used most often in enterprise-level applications
- where it’s necessary to reuse as much presentation logic as
- possible. Applications with very complex views and a great deal of
- user interaction may find that MVC doesn’t quite fit the bill here
- as solving this problem may mean heavily relying on multiple
- controllers. In MVP, all of this complex logic can be encapsulated
- in a presenter, which can simplify maintenance greatly.
- </para>
- <para>
- As MVP views are defined through an interface and the interface is
- technically the only point of contact between the system and the
- view (other than a presenter), this pattern also allows developers
- to write presentation logic without needing to wait for designers to
- produce layouts and graphics for the application.
- </para>
- <para>
- Depending on the implementation, MVP may be more easy to
- automatically unit test than MVC. The reason often cited for this is
- that the presenter can be used as a complete mock of the
- user-interface and so it can be unit tested independent of other
- components. In my experience this really depends on the languages
- you are implementing MVP in (there’s quite a difference between
- opting for MVP for a JavaScript project over one for say, ASP.net).
- </para>
- <para>
- At the end of the day, the underlying concerns you may have with MVC
- will likely hold true for MVP given that the differences between
- them are mainly semantic. As long as you are cleanly separating
- concerns into models, views and controllers (or presenters) you
- should be achieving most of the same benefits regardless of the
- pattern you opt for.
- </para>
- </sect1>
- <sect1 id="mvc-mvp-and-backbone.js">
- <title>MVC, MVP and Backbone.js</title>
- <para>
- There are very few, if any architectural JavaScript frameworks that
- claim to implement the MVC or MVP patterns in their classical form
- as many JavaScript developers don’t view MVC and MVP as being
- mutually exclusive (we are actually more likely to see MVP strictly
- implemented when looking at web frameworks such as ASP.net or GWT).
- This is because it’s possible to have additional presenter/view
- logic in your application and yet still consider it a flavor of MVC.
- </para>
- <para>
- Backbone contributor <ulink url="http://ireneros.com/">Irene
- Ros</ulink> subscribes to this way of thinking as when she separates
- Backbone views out into their own distinct components, she needs
- something to actually assemble them for her. This could either be a
- controller route (such as a <literal>Backbone.Router</literal>,
- covered later in the book) or a callback in response to data being
- fetched.
- </para>
- <para>
- That said, some developers do however feel that Backbone.js better
- fits the description of MVP than it does MVC . Their view is that:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- The presenter in MVP better describes the
- <literal>Backbone.View</literal> (the layer between View
- templates and the data bound to it) than a controller does
- </para>
- </listitem>
- <listitem>
- <para>
- The model fits <literal>Backbone.Model</literal> (it isn’t that
- different from the classical MVC
- <quote>Model</quote>)<literallayout></literallayout>
- </para>
- </listitem>
- <listitem>
- <para>
- The views best represent templates (e.g Handlebars/Mustache
- markup templates)
- </para>
- </listitem>
- </itemizedlist>
- <para>
- A response to this could be that the view can also just be a View
- (as per MVC) because Backbone is flexible enough to let it be used
- for multiple purposes. The V in MVC and the P in MVP can both be
- accomplished by <literal>Backbone.View</literal> because they’re
- able to achieve two purposes: both rendering atomic components and
- assembling those components rendered by other views.
- </para>
- <para>
- We’ve also seen that in Backbone the responsibility of a controller
- is shared with both the Backbone.View and Backbone.Router and in the
- following example we can actually see that aspects of that are
- certainly true.
- </para>
- <para>
- Here, our Backbone <literal>PhotoView</literal> uses the Observer
- pattern to <quote>subscribe</quote> to changes to a View’s model in
- the line <literal>this.model.bind('change',...)</literal>. It also
- handles templating in the <literal>render()</literal> method, but
- unlike some other implementations, user interaction is also handled
- in the View (see <literal>events</literal>).
- </para>
- <programlisting language="javascript">
- var PhotoView = Backbone.View.extend({
- //... is a list tag.
- tagName: "li",
- // Pass the contents of the photo template through a templating
- // function, cache it for a single photo
- template: _.template($('#photo-template').html()),
- // The DOM events specific to an item.
- events: {
- "click img" : "toggleViewed"
- },
- // The PhotoView listens for changes to its model, re-rendering. Since there's
- // a one-to-one correspondence between a **Photo** and a **PhotoView** in this
- // app, we set a direct reference on the model for convenience.
- initialize: function() {
- _.bindAll(this, 'render');
- this.model.bind('change', this.render);
- this.model.bind('destroy', this.remove);
- },
- // Re-render the photo entry
- render: function() {
- $(this.el).html(this.template(this.model.toJSON()));
- return this;
- },
- // Toggle the `"viewed"` state of the model.
- toggleViewed: function() {
- this.model.viewed();
- }
- });
- </programlisting>
- <para>
- Another (quite different) opinion is that Backbone more closely
- resembles
- <ulink url="http://martinfowler.com/eaaDev/uiArchs.html#ModelViewController">Smalltalk-80
- MVC</ulink>, which we went t…
Large files files are truncated, but you can click here to view the full file