design patterns for
Large-scale JAVASCRIPT

by Tiago Garcia @ Avenue Code
tgarcia@avenuecode.com

Jan 27th, 2014

AGENDA


  • Design Patterns
  • Javascript Design Patterns
    • Constructor
    • Module
    • Revealing Module
    • Façade
    • Observer
    • Mediator
  • Large-scale Javascript
______________________________________________
Design Patterns for Javascript

AGENDA


    • Singleton
    • Prototype
    • Command
    • Factory Method
    • Abstract Factory
    • Mixin
    • Decorator
    • Flyweight
    • Lazy Loading
______________________________________________
Design Patterns for Javascript

Prerequisites


  • Intermediate Javascript
  • Familiarity with Design Patterns
______________________________________________
Design Patterns for Javascript

design patterns


  • Hyperspace: the next dimension above.
  • We can only see up to the current dimension.
  • Consider 3 dimensions for a browser:
    • Rendering: HTML/CSS.
    • Elements: DOM.
    • Behavior: JS.
  • The 4th dimension is its hyperspace.
    How would it be?
______________________________________________
 Boosting the client-side with Backbone.js

javascript design patterns


  • Application ends:
    • Front-end: interacts with a human.
    • Back-end: handles business logic and data/services access.
  • Application sides:
    • Client-side: runs on user browser/device.
    • Server-side: runs on a server.


THEY ARE NOT THE SAME THING!

______________________________________________
 Boosting the client-side with Backbone.js

constructor


  • Isolated web-apps (client-side only):
    • Only front-end. Ex: "BMI calculator".
    • Front-end and back-end. Ex: "TODO list manager" persisting on HTML5 local storage on the browser.
______________________________________________
 Boosting the client-side with Backbone.js

client-side vs. server-side


  • Integrated web apps (client-side and server-side):
    • Front-end on client-side + back-end on server-side. Response is hypertext over HTTP. Ex: "TODO list manager" in a web framework (Struts, JSF, Rails).
    • Front-end and back-end on client-side + REST back-end on server-side. Response is data over HTTP. Ex: "Trello" implemented in Backbone.js.
______________________________________________
 Boosting the client-side with Backbone.js

REST


  • REpresentational State Transfer.
  • Stateless architectural style for distributed systems, based on HTTP protocol:
    • HTTP methods are verbs (actions).
    • URIs are nouns (resources).
    • HTTP status codes are meaningful actions responses, like 200 (ok), 404 (not found), 500 (internal server error).
______________________________________________
 Boosting the client-side with Backbone.js

REST


  • REST actions addressed today:
    • HTTP GET:  retrieves a resource. Ex:  GET /users/1 retrieves the user which id = 1.
    • HTTP POST: creates a resource. Ex:  POST /users creates an user (data on request body).
    • HTTP PUT: updates a resource. Ex:   PUT /users/1 updates the user which id = 1 (data on req. body).
    • HTTP DELETE: removes a resource. Ex:  DELETE /users/1 removes the user which id = 1.
______________________________________________
 Boosting the client-side with Backbone.js

JSON


  • JavaScript Object Notation.
  • Universal format of data transference in JavaScript.
  • Reduced size, simplified format, easy to parse -> good alternative to XML.
{
  "name": "R2-D2",
  "owners": ["Anakin", "Leia", "Luke"],
  "attributes": {
    "height": 0.96,
    "mass": 32
  }
}					
______________________________________________
 Boosting the client-side with Backbone.js

MVC


  • Model-View-Controller.
  • Architectural design pattern that leverages better application organization through separation of concerns:
    • Model: business data.
    • View: user interface.
    • Controller: connection and data input logic.
______________________________________________
 Boosting the client-side with Backbone.js

MVC in Javascript


  • Avoid "spaghetti code" (hard to read and maintain for the lack of structure).
  • Overall maintainability is strongly improved. It  makes it clear to identify where to change the code.
  • Enables more objective unit tests.
  • Modularity allows better distribution of tasks among the team.


MVC IS OUR HYPERSPACE!!

______________________________________________
 Boosting the client-side with Backbone.js

WEB FRAMEWORKS vs. client-side apps

  • Server-side web frameworks:
    • Actions life cycle is managed and routed on the server-side.
    • Server-side templates generating HTML from data.
    • HTTP response transmitting hypertext (HTML).
    • Every action demands a page reload.
    • Actions are synchronous.
______________________________________________
 Boosting the client-side with Backbone.js

WEB FRAMEWORKS vs. client-side apps

  • Client-side apps:
    • Actions life cycle is managed and routed on the client-side.
    • HTTP response transmitting data (JSON, XML, etc...).
    • Client-side templates generating HTML from data.
    • Actions DON'T demand any page reload.
    • Actions can be asynchronous.
______________________________________________
 Boosting the client-side with Backbone.js

backbone.js


  • Javascript library that provides structure to client-side applications based on REST APIs using JSON.
  • Created in 2010, it is currently used in big websites such as Airbnb, BitTorrent, Digg, Foursquare, Hulu, LinkedIn mobile, Pinterest, Trello, Walmart and Wordpress.
  • Depends on Underscore.js and jQuery (or similar libs such as Zepto.js, with varying degrees of compatibility).
______________________________________________
 Boosting the client-side with Backbone.js

backbone.js


  • SPA (Single-Page Application): architectural style about doing a single page load for the whole application.
  • Elements: Model, Collection, View and Router.


Backbone.js isn't a classic MVC framework...

...but it belongs to MV* family, which similar goals!!

______________________________________________
 Boosting the client-side with Backbone.js

Model


  • Stores and manipulates data.
  • Communicates with REST APIs.
  • Supports parsing, translation, validation and business logic processing.
var CardModel = Backbone.Model.extend({
  urlRoot : '/api/cards'
});							
  • urlRoot specifies the base URL for REST calls, which will precede the REST actions.
______________________________________________
 Boosting the client-side with Backbone.js

Model


  • REST methods:
    • fetch(options): Retrieves an entity via HTTP GET.
    • save(attributes, options): Creates an entity via HTTP POST (if the object doesn't have an id yet) or updates an entity via HTTP PUT (if the object has an id already).
    • destroy(options): Removes an entity via HTTP DELETE.
______________________________________________
 Boosting the client-side with Backbone.js

Model


  • Parâmetros:
    • attributes: Object containing data to be saved.
    • options: Object containing configuration such as: 
      • url: Connection URL with the server-side, overwriting urlRoot.
      • success: Callback function for success response.
      • error: Callback function for error response or timeout .
______________________________________________
 Boosting the client-side with Backbone.js

Model


var model = new CardModel({
  id: 1
});

// GET /api/cards/1
model.fetch({
  success: function(model, response, options) {
    console.log('Success! Model = ' + model.toJSON());
  },
  error: function(model, response, options) {
    console.log('Error or timeout.');
  }
});							
______________________________________________
 Boosting the client-side with Backbone.js

Model


  • Some common methods:
    • get(attribute): Gets the value of an attribute from the Model. Ex: card.get('title');
    • set(attribute, value): Sets a value for an attribute on the Model. Ex: card.set('title', 'Project X');
    • toJSON(): Returns a copy of the Model data in JSON. Ex: card.toJSON();
______________________________________________
 Boosting the client-side with Backbone.js

Collection


  • Ordered list of Models.
  • Creates models from a JSON array.
  • Implements array methods from Underscore.js library.
var CardCollection = Backbone.Collection.extend({
  model : CardModel,
  url : '/api/cards'
});							
  • model specifies the Model to be created.
  • url specifies the base URL for REST calls, which will precede the REST actions.
______________________________________________
 Boosting the client-side with Backbone.js

Collection


  • Collections complement the REST API from Models with this method:
    • fetch(options): Retrieves an array of entities via HTTP GET, populates each entity as a Model and inserts it in the Collection.
______________________________________________
 Boosting the client-side with Backbone.js

Collection


var cardCollection = new CardCollection();

// GET /api/cards
cardCollection.fetch({
  success: function(collection, response, options) {
    console.log('Success! Collection = ' + 
                collection.toJSON());
  },
  error: function(collection, response, options) {
    console.log('Error or timeout.');
  }
});    						
______________________________________________
 Boosting the client-side with Backbone.js

Collection


  • Some common methods:
    • get(id): Retrieves a Model a from its id. Ex: collection.get(12);
    • at(index): Retrieves a Model from its position on the Collection. Ex: collection.at(1);
    • add(model): Adds a Model to the Collection. Ex: collection.add({'title', 'Project X'});
    • remove(id): Removes a Model from the Collection. Ex: collection.remove(12);
______________________________________________
 Boosting the client-side with Backbone.js

Collection


  • Some common methods:
    • toJSON(): Returns a copy of the Collection data in JSON. Ex: collection.toJSON();
    • where(attributes): Returns just the Collection elements which match the given criteria. Ex: collection.where({'type': 'PROJECT'});
    • pluck(attribute): Returns an array with extracted values from Collection elements, based on the given attribute. Ex: collection.pluck('title');
______________________________________________
 Boosting the client-side with Backbone.js

View


  • Manages the presentation logic and events.
  • Renders an HTML template which can be added to the DOM, consuming data from Models or Collections.
  • The HTML template can be dynamically generated.
______________________________________________
 Boosting the client-side with Backbone.js

View


  • Main attributes to be implemented:
    • events: Events mapping object, like this:
      'CSS selector': function / 'function'
    • render(): Method that should contain all the View logic, in three steps:
      • Retrieving/preparing the HTML template.
      • Rendering the HTML template from a Model or Collection.
      • Inserting the rendering result into el attribute.
______________________________________________
 Boosting the client-side with Backbone.js

View


  • Some common View attributes:
    • el: HTML element rendered by this View. It can be accessed via $el as a jQuery/Zepto.js object.
    • id: The id attribute from el.
    • className: The class attribute from el
    • tagName: The HTML tag to be used by el.
    • remove(): Removes the View from the DOM and remove all event listeners binded to it.
______________________________________________
 Boosting the client-side with Backbone.js

View


var CardView = Backbone.View.extend({
  events: {
    'click button.close': function(e) {
      e.preventDefault();
      this.remove();
    }
  },
  render: function() {
    var result = 
       '<h1>' + this.model.get('title') + '</h1>' +
       '<button class="close">Close</button>');
    this.$el.html(result);
  }
});    						
______________________________________________
 Boosting the client-side with Backbone.js


View


  • View parameters:
    • el: An existing HTML element can be provided to receive the content rendered by the View.
    • model: The Model to be consumed by render().
    • collection: The Collection to be consumed by render().
______________________________________________
 Boosting the client-side with Backbone.js


View


var cardModel = new CardModel({ id: 1 });

cardModel.fetch({
  success: function(model, response, options) {
    var cardView = new CardView({
      model: cardModel
    );
    cardView.render();
    $('#contents').append(cardView.el);
  },
  error: function(model, response, options) {
    console.log('Error or timeout.');
  }
});							
______________________________________________
 Boosting the client-side with Backbone.js


Router


  • Allows for URL handling and routing.
  • Controls the navigation history.
  • Avoids direct requests to the server-side.
  • Main attribute:
    • routes: Mapping routes object, like this:
      'uri': function / 'function'
______________________________________________
 Boosting the client-side with Backbone.js

Router


  • Some common methods:
    • route(path, name): Also inserts a route, but can use regex. Ex: router.route(/^card/(\d+)$/, 'viewCard');
    • navigate(path, options): Navigates to a URL. In order to also trigger the route, use options as {trigger: true}. Ex: router.navigate('/card/32', {trigger: true});
    ______________________________________________
     Boosting the client-side with Backbone.js

Router


var AppRouter = Backbone.Router.extend({
  routes : {
    '' : 'viewAll',
    'card/:id' : 'viewCard',
    '*path' : 'viewAll'
  },

  viewAll: function() { ... },

  viewCard: function(id) { ... }
});    			
______________________________________________
 Boosting the client-side with Backbone.js

Router


  • It is necessary to call Backbone.history.start()
    to start the routes monitoring by the Routers.
  • Pass {pushState: true} to it in order to use HTML5 pushState. Otherwise, the routing would use # after the URL query string..
var appRouter = new AppRouter();

Backbone.history.start({
  pushState : true
});							
______________________________________________
 Boosting the client-side with Backbone.js

Dynamic templates


  • On the View, the HTML template can be generated by any Javascript templating library such as Underscore.js, Mustache, Handlebars.js, dust.js, etc...
  • It is the same idea of PHP, JSP, ERB, ASP - but now on the client-side.
  • It is much more maintainable then concatenated strings.
______________________________________________
 Boosting the client-side with Backbone.js

Dynamic templates


  • Handlebars.js: performative, flexible and easy to learn and to handle alternative.
{{#if children}}
  <ul>
    {{#each children}}
      <li>{{title}}: {{description}}</li>
    {{/each}}
  </ul>
{{else}}
  <p>There is no items!</p>
{{/if}}
  • Will be covered on a next AC talk by Alysson Ferreira!
______________________________________________
 Boosting the client-side with Backbone.js

Conclusion


  • Client-side apps aim to reproduce the desktop experience on the web.
  • Client-side apps can drastically reduce the time waited by the user for a feedback.
  • Hence, the chances for the user to stay on the system are greatly increased.
  • Backbone.js is a mature MV* alternative to structure client-side apps.
______________________________________________
 Boosting the client-side with Backbone.js

Learn more


______________________________________________
Design Patterns for Javascript

CHALLENGE

Write a multiple-choice quizz about a subject of your preference as a client-side app using Backbone.js.

  1. The user name and email should be collected.
  2. 5 possible answers per question.
  3. Either just 1 or up to 3 answers per time.
  4. At least 5 questions on the quizz.
  5. Lastly the user must see a graph of all questions and answers  from all users with % for each answer.
  6. Any approach for persistence, as long it uses Models (REST backend, local storage, session object, cookie...).
  7. Send me the solution in a GitHub repo. 
_____________________________________________
 Boosting the client-side with Backbone.js

Copy of Design Patterns for Large-Scale Javascript

By Tiago Romero Garcia

Copy of Design Patterns for Large-Scale Javascript

Learn the essential design patterns for large-scale Javascript applications. By Tiago Garcia

  • 2,136