$30 off During Our Annual Pro Sale. View Details »

Large-scale JavaScript Application Architecture

Addy Osmani
November 16, 2011
110k

Large-scale JavaScript Application Architecture

Developers creating JavaScript applications these days usually use a combination of MVC, modules, widgets and plugins for their architecture. They also use a DOM manipulation library like jQuery.

Whilst this works great for apps that are built at a smaller-scale, what happens when your project really starts to grow?

In this talk, I present an effective set of design patterns for large-scale JavaScript (and jQuery) application architecture that have previously been used at both AOL and Yahoo amongst others.

You'll learn how to keep your application logic truly decoupled, build modules that can exist on their own or be dropped into other projects and future-proof your code in case you need to switch to a different DOM library in the future.

Addy Osmani

November 16, 2011
Tweet

Transcript

  1. View Slide

  2. Today, we’re going to look at how to
    create small to medium jQuery apps and
    large to really large JavaScript apps.

    View Slide

  3. jQuery is a fantastic DOM manipulation
    library.

    View Slide

  4. However, unlike Dojo it doesn’t provide
    recommendations for application
    structure or how to organise your code.
    That’s not it’s job.

    View Slide

  5. Remember: there are situations where it
    makes sense to use just jQuery..
    and those where it makes more sense to
    use additional tools like Backbone or
    alternatives (e.g Dojo).

    View Slide

  6. What are we looking at today?
    The Schedule
    Design Patterns jQuery & MVC
    Frameworks
    Resources
    Scalable Application
    Architecture
    Patterns for building
    really large apps
    JavaScript Patterns
    For organising
    applications

    View Slide

  7. Part I: Patterns - A New Hope.

    View Slide

  8. Reusable solutions that can be applied to commonly
    occurring problems in software design and architecture.
    Design Patterns
    “We search for some kind of harmony between two intangibles: a form we have not yet
    designed and a context we cannot properly describe’
    - Christopher Alexander, the father of design patterns.

    View Slide

  9. Patterns are generally proven to have successfully solved problems in the past.
    They’re proven
    Solid
    Reliable
    approaches
    Re ect
    experience
    Represent
    insights

    View Slide

  10. Patterns can be picked up, improved and adapted without great effort.
    They’re reusable
    Out-of-the-box
    solutions
    Easily adapted
    Incredibly exible

    View Slide

  11. Patterns provide us a means to describing approaches or structures.
    They’re expressive
    Problem agnostic
    Common vocabulary
    for expressing
    solutions elegantly.
    Easier than describing
    syntax and semantics

    View Slide

  12. Patterns genuinely can help avoid some of the common pitfalls of development.
    They offer value
    Prevent minor issues
    that can cause
    Major problems
    later down the line

    View Slide

  13. Get ‘Essential JavaScript Design Patterns’. It’s Free!
    For More Info
    If you nd it useful, de nitely
    check out:
    http://bit.ly/essentialjsdesignpatterns

    View Slide

  14. Part II: The JavaScript Strikes Back

    View Slide

  15. “I have all this jQuery code that does a
    few distinct things..but I’m not entirely
    sure how to organise it. What can I do?”

    View Slide

  16. Options for structuring your jQuery applications
    jQuery & MVC

    View Slide

  17. How do you structure your application?
    Architecture
    • Architecture patterns describe concepts for the
    structure of an application
    • Certain patterns can be applied to both the
    client and server-side
    • Most client-side architecture patterns have
    roots in the server-side

    View Slide

  18. The pattern most commonly used on the
    front-end these days is ‘MVC’.
    *It’s of course not the *only* option, just the most frequently implemented.

    View Slide

  19. Separates applications into three main concerns:
    The MVC Pattern
    Models Views Controllers

    View Slide

  20. Manage the behaviour of the application data
    MVC: Models
    • Represent knowledge and data
    • Respond to changes of state
    • Isolated from views and controllers
    • Sometimes grouped (e.g collections)

    View Slide

  21. Render models into a form suitable for user interaction
    MVC: Views
    • In most cases can be considered the UI
    • Typically render to a speci c user interface
    element
    • Many frameworks rely on templating for this
    • Multiple views can exist for single models

    View Slide

  22. Receive input and instruct models and views to respond accordingly
    MVC: Controllers
    • Sits between models and views
    • (May) perform business logic and data
    manipulation
    • It’s role in client-side MVC heavily varies
    • Some replace it with a router, others use it as a
    logic handler

    View Slide

  23. Converting spaghetti code to use MVC isn’t all that hard..
    How Does This Work?
    Models
    Views
    Controllers
    Spaghetti code
    What unique data is
    represented in my
    app? e.g a picture, a
    person
    What does the user need to
    be able to see and do?
    What (repeatable) output can I
    shift to JS templating?
    (varies) If a router, what
    happens when a route is
    navigated to? e.g. /#admin

    View Slide

  24. Converting spaghetti code to use MVC isn’t all that hard..
    How Does This Work?
    Models
    Views
    Controllers
    Spaghetti code
    What unique data is
    represented in my
    app? e.g a picture, a
    person
    What does the user need to
    be able to see and do?
    What (repeatable) output can I
    shift to JS templating?
    (varies) If a router, what
    happens when a route is
    navigated to? e.g. /#admin

    View Slide

  25. Converting spaghetti code to use MVC isn’t all that hard..
    How Does This Work?
    Models
    Views
    Controllers
    Spaghetti code
    What unique data is
    represented in my
    app? e.g a picture, a
    person
    What does the user need to
    be able to see and do?
    What (repeatable) output can I
    shift to JS templating?
    (varies) If a router, what
    happens when a route is
    navigated to? e.g. /#admin

    View Slide

  26. On the client-side, I prefer to refer to this
    pattern as MVV (Model-View-Variation).
    All JavaScript ‘MVC’ frameworks seem to
    interpret MVC differently.

    View Slide

  27. Frameworks and libraries that provide MVC implementations
    MVC Implementations
    • Backbone.js
    • Spine.js
    • JavaScriptMVC
    • AngularJS
    • SproutCore
    • YUILibrary
    • Broke.js
    • Fidel.js
    • Sammy.js
    • KnockoutJS (MVVM)

    View Slide

  28. A quick overview of what’s available
    MVC Frameworks
    • Backbone.js - light, mature, popular.
    • JavaScriptMVC - MVC, integrated dev tools
    • Spine.js - light, best option for CoffeeScript devs
    • SproutCore - 2.0 is also light, good docs
    • AngularJS - light, relies on data-bindings
    • Sammy.js - routes/controllers but no MV. Better
    for bootstrapping just the parts needed

    View Slide

  29. To help make deciding on an MVC
    framework easier, I created TodoMVC.

    View Slide

  30. http://addyosmani.github.com/todomvc
    http://addyosmani.github.com/todomvc
    Same app, different frameworks.

    View Slide

  31. With the same functionality, it’s easier to compare implementations.
    Easy to compare

    View Slide

  32. Moving beyond MVC, there are times
    when you want to further break down
    your application. Patterns can help with
    this.

    View Slide

  33. Writing code that’s expressive, encapsulated
    & structured
    JavaScript Patterns

    View Slide

  34. Interchangeable single-parts of a larger system that can be
    easily re-used. In JS we use the module pattern.
    Modules
    “Anything can be de ned as a reusable module”
    - Nicholas Zakas, author ‘Professional JavaScript For Web Developers’

    View Slide

  35. Immediately invoked function expressions (or self-executing anonymous functions)
    Stepping stone: IIFE
    (function() {
    // code to be immediately invoked
    }()); // Crockford recommends this way
    (function() {
    // code to be immediately invoked
    })(); // This is just as valid
    (function( window, document, undefined ){
    //code to be immediately invoked
    })( this, this.document);
    (function( global, undefined ){
    //code to be immediately invoked
    })( this );

    View Slide

  36. This is great, but..

    View Slide

  37. View Slide

  38. There isn’t a true sense of it in JavaScript.
    Privacy In JavaScript
    No Access Modi ers
    Variables & Methods
    can’t be ‘public’
    Variables & Methods
    can’t be ‘private’

    View Slide

  39. The typical module pattern is where immediately invoked function expressions (IIFEs) use
    execution context to create ‘privacy’. Here, objects are returned instead of functions.
    Module Pattern
    var basketModule = (function() {
    var basket = []; //private
    return { //exposed to public
    addItem: function(values) {
    basket.push(values);
    },
    getItemCount: function() {
    return basket.length;
    },
    getTotal: function(){
    var q = this.getItemCount(),p=0;
    while(q--){
    p+= basket[q].price;
    }
    return p;
    }
    }
    }());
    • In the pattern, variables
    declared are only
    available inside the
    module.
    • Variables de ned within
    the returning object are
    available to everyone
    • This allows us to simulate
    privacy

    View Slide

  40. Inside the module, you'll notice we return an object. This gets automatically assigned to basketModule so
    that you can interact with it as follows:
    Sample usage
    //basketModule is an object with properties which can also be methods
    basketModule.addItem({item:'bread',price:0.5});
    basketModule.addItem({item:'butter',price:0.3});
    console.log(basketModule.getItemCount());
    console.log(basketModule.getTotal());
    //however, the following will not work:
    // (undefined as not inside the returned object)
    console.log(basketModule.basket);
    //(only exists within the module scope)
    console.log(basket);

    View Slide

  41. Dojo attempts to provide 'class'-like functionality through dojo.declare, which can be used for amongst
    other things, creating implementations of the module pattern. Powerful when used with dojo.provide.
    Module Pattern: Dojo
    // traditional way
    var store = window.store || {};
    store.basket = store.basket || {};
    // another alternative..
    // using dojo.setObject (with basket as a module of the store namespace)
    dojo.setObject("store.basket.object", (function() {
    var basket = [];
    function privateMethod() {
    console.log(basket);
    }
    return {
    publicMethod: function(){
    privateMethod();
    }
    };
    }()));

    View Slide

  42. In the following example, a library function is de ned which declares a new library and automatically binds
    up the init function to document.ready when new libraries (ie. modules) are created.
    Module Pattern: jQuery
    function library(module) {
    $(function() {
    if (module.init) {
    module.init();
    }
    });
    return module;
    }
    var myLibrary = library(function() {
    return {
    init: function() {
    /*implementation*/
    }
    };
    }());

    View Slide

  43. A YUI module pattern implementation that follows the same general concept.
    Module Pattern: YUI
    YAHOO.store.basket = function () {
    //"private" variables:
    var myPrivateVar = "I can be accessed only within YAHOO.store.basket .";
    //"private" method:
    var myPrivateMethod = function () {
    YAHOO.log("I can be accessed only from within YAHOO.store.basket");
    }
    return {
    myPublicProperty: "I'm a public property.",
    myPublicMethod: function () {
    YAHOO.log("I'm a public method.");
    //Within basket, I can access "private" vars and methods:
    YAHOO.log(myPrivateVar);
    YAHOO.log(myPrivateMethod());
    //The native scope of myPublicMethod is store so we can
    //access public members using "this":
    YAHOO.log(this.myPublicProperty);
    }
    };
    }();

    View Slide

  44. Another library that can similarly use the module pattern.
    Module Pattern: ExtJS
    // define a namespace
    Ext.namespace('myNamespace');
    // define a module within this namespace
    myNameSpace.module = function() {
    // recommended that you don't directly access the DOM
    // from here as elements don't exist yet. Depends on
    // where/how you're waiting for document load.
    // private variables
    // private functions
    // public API
    return {
    // public properties
    // public methods
    init: function() {
    console.log('module initialised successfully');
    }
    };
    }(); // end of module

    View Slide

  45. Take the concept of reusable JavaScript modules further with the
    Asynchronous Module De nition.
    Better: AMD
    Mechanism for de ning
    asynchronously loadable
    modules & dependencies
    Non-blocking, parallel
    loading and well de ned.
    Stepping-stone to the
    module system proposed
    for ES Harmony

    View Slide

  46. de ne allows the de nition of modules with a signature of
    de ne(id /*optional*/, [dependencies], factory /*module instantiation fn*/);
    AMD: de ne()
    /* wrapper */
    define(
    /*module id*/
    'myModule',
    /*dependencies*/
    ['foo','bar','foobar'],
    /*definition for the module export*/
    function (foo, bar, foobar) {
    /*module object*/
    var module = {};
    /*module methods go here*/
    module.hello = foo.getSomething();
    module.world = bar.doSomething();
    /*return the defined module object*/
    return module;
    }
    );

    View Slide

  47. require is used to load code for top-level JS les or inside modules for
    dynamically fetching dependencies
    AMD: require()
    /* top-level: the module exports (one, two) are passed as
    function args to the callback.*/
    require(['one', 'two'], function (one, two) {
    });
    /* inside: complete example */
    define('three', ['one', 'two'], function (one, two) {
    /*require('string') can be used inside the function
    to get the module export of a module that has
    already been fetched and evaluated.*/
    var temp = require('one');
    /*This next line would fail*/
    var bad = require('four');
    /* Return a value to define the module export */
    return function () {};
    });

    View Slide

  48. AMD modules can be used with
    RequireJS and curl.js amongst other
    script loaders.
    They’re compatible with Dojo, MooTools
    and even jQuery.

    View Slide

  49. A very simple AMD module using jQuery and the color plugin
    AMD + jQuery
    define(["jquery", "jquery.color", "jquery.bounce"], function($) {
    //the jquery.color and jquery.bounce plugins have been loaded
    // not exposed to other modules
    $(function() {
    $('#container')
    .animate({'backgroundColor':'#ccc'}, 500)
    .bounce();
    });
    // exposed to other modules
    return function () {
    // your module's functionality
    };
    });

    View Slide

  50. Recommended by Require.js author James Burke
    AMD/UMD jQuery Plugin
    (function(root, factory) {
    if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
    } else if (typeof define === 'function' &&
    define.amd) {
    // AMD. Use a named plugin in case this
    // file is loaded outside an AMD loader,
    // but an AMD loader lives on the page.
    define('myPlugin', ['jquery'], factory);
    } else {
    // Browser globals
    factory(root.jQuery);
    }
    }(this, function($) {
    $.fn.myPlugin = function () {};
    }));

    View Slide

  51. Want to see a Backbone.js + RequireJS +
    AMD + jQuery demo? Hang on until the end.
    https://github.com/addyosmani/backbone-aura
    *or look at:

    View Slide

  52. Another easy to use module system with wide adoption server-side
    Alternative: CommonJS
    CommonJS
    Working group
    designing, prototyping,
    standardizing JS APIs
    Format widely accepted
    on a number of server-side
    platforms (Node)
    Competing standard. Tries
    to solve a few things AMD
    doesn’t.

    View Slide

  53. They basically contain two parts: an exports object that contains the objects a
    module wishes to expose and a require function that modules can use to import
    the exports of other modules
    CommonJS Modules
    /* here we achieve compatibility with AMD and CommonJS
    using some boilerplate around the CommonJS module format*/
    (function(define){
    define(function(require,exports){
    /*module contents*/
    var dep1 = require("foo");
    var dep2 = require("bar");
    exports.hello = function(){...};
    exports.world = function(){...};
    });
    })(typeof define=="function"? define:function(factory)
    {factory(require,exports)});

    View Slide

  54. A module format proposed for EcmaScript Harmony with goals such as static
    scoping, simplicity and usability. This isn’t nal.
    ES Harmony Modules
    // Basic module
    module SafeWidget {
    import alert from Widget;
    var _private ="someValue";
    // exports
    export var document = {
    write: function(txt) {
    alert('Out of luck, buck');
    },
    ...
    };
    }
    // Remote module
    module JSONTest from 'http://json.org/modules/json2.js';

    View Slide

  55. A module created using Google’s recently proposed Dart
    DART modules
    // 17,000 lines of code
    // couldn’t fit on the slides
    // Sorry, guise!

    View Slide

  56. Modules are regularly used in MVC
    applications..but there are other patterns
    that can make building large apps easier
    too.

    View Slide

  57. Remember..jQuery generally plays a
    smaller role in larger-apps than most
    people might think.

    View Slide

  58. Convenient, high-level interfaces to larger bodies of code
    that hide underlying complexity
    Facade Pattern
    “When you put up a facade, you're usually creating an outward appearance which conceals a
    different reality. Think of it as simplifying the API presented to other developers”
    - Essential JavaScript Design Patterns

    View Slide

  59. A higher-level facade is provided to our underlying module, without directly exposing methods.
    Facade Implementation
    var module = (function() {
    var _private = {
    i:5,
    get : function() {
    console.log('current value:' + this.i);
    },
    set : function( val ) {
    this.i = val;
    },
    run : function() {
    console.log('running');
    },
    jump: function(){
    console.log('jumping');
    }
    };
    return {
    facade : function( args ) {
    _private.set(args.val);
    _private.get();
    if ( args.run ) {
    _private.run();
    }
    }
    }
    }());
    module.facade({run: true, val:10}); //outputs current value: 10, running

    View Slide

  60. var module = (function() {
    var _private = {
    i:5,
    get : function() {
    console.log('current value:' + this.i);
    },
    set : function( val ) {
    this.i = val;
    },
    run : function() {
    console.log('running');
    },
    jump: function(){
    console.log('jumping');
    }
    };
    return {
    facade : function( args ) {
    _private.set(args.val);
    _private.get();
    if ( args.run ) {
    _private.run();
    }
    }
    }
    }());
    module.facade({run: true, val:10}); //outputs current value: 10, running
    A higher-level facade is provided to our underlying module, without directly exposing methods.
    Facade Implementation
    We’re really just interested
    in this part.

    View Slide

  61. A higher-level facade is provided to our underlying module, without directly exposing methods.
    Facade Implementation
    return {
    facade : function( args ) {
    // set values of private properties
    _private.set(args.val);
    // test setter
    _private.get();
    // optional: provide a simple interface
    // to internal methods through the
    // facade signature
    if ( args.run ) {
    _private.run();
    }
    }
    }
    Limited public API of functionality.
    Differs greatly from the reality of the
    implementation.

    View Slide

  62. A structural pattern found in many JavaScript libraries and frameworks (eg. jQuery).
    A Facade
    Simpli es usage
    through a limited,
    more readable API
    Hides the inner-
    workings of a library.
    Allows implementation
    to be less important.
    This lets you be more
    creative behind the
    scenes.

    View Slide

  63. How does it differ from the module pattern?
    Facade Pattern
    • Differs from the module pattern as the exposed
    API can greatly differ from the public/private
    methods de ned
    • Has many uses including application security
    as we’ll see a little later in the talk

    View Slide

  64. Encapsulates how disparate modules interact with each
    other by acting as an intermediary
    Mediator Pattern
    “Mediators are used when the communication between modules may be complex, but
    is still well de ned”
    - Essential JavaScript Design Patterns

    View Slide

  65. I always nd this mediator analogy helps when discussing this pattern:
    Air Traf c Control
    The tower handles
    what planes can take
    off and land
    All communication done
    from planes to tower,
    not plane to plane
    Centralised controller
    is key to this success.
    Similar to mediator.

    View Slide

  66. Promotes loose coupling. Helps solve module inter-dependency issues.
    A Mediator
    Allow modules to
    broadcast or listen for
    noti cations without
    worrying about the system.
    Noti cations can be
    handled by any number of
    modules at once.
    Typically easier to add or
    remove features to loosely
    coupled systems like this.

    View Slide

  67. One possible implementation, exposing publish and subscribe capabilities.
    Mediator Implementation
    var mediator = (function(){
    var subscribe = function(channel, fn){
    if (!mediator.channels[channel])mediator.channels[channel] = [];
    mediator.channels[channel].push({ context: this, callback:fn });
    return this;
    },
    publish = function(channel){
    if (!mediator.channels[channel]) return false;
    var args = Array.prototype.slice.call(arguments, 1);
    for (var i = 0, l = mediator.channels[channel].length; i var subscription = mediator.channels[channel][i];
    subscription.callback.apply(subscription.context,args);
    }
    return this;
    };
    return {
    channels: {},
    publish: publish,
    subscribe: subscribe,
    installTo: function(obj){
    obj.subscribe = subscribe;
    obj.publish = publish;
    }
    };
    }());

    View Slide

  68. Usage of the implementation from the last slide.
    Example
    //Pub/sub on a centralized mediator
    mediator.name = "tim";
    mediator.subscribe('nameChange', function(arg){
    console.log(this.name);
    this.name = arg;
    console.log(this.name);
    });
    mediator.publish('nameChange', 'david'); //tim, david
    //Pub/sub via third party mediator
    var obj = { name: 'sam' };
    mediator.installTo(obj);
    obj.subscribe('nameChange', function(arg){
    console.log(this.name);
    this.name = arg;
    console.log(this.name);
    });
    obj.publish('nameChange', 'john'); //sam, john

    View Slide

  69. Part III: Return of the patterns

    View Slide

  70. Strategies for decoupling and future-proo ng the structure
    of your application. Let’s build empires.
    Scalable Application
    Architecture
    Thanks to Nicholas Zakas, Rebecca Murphey, John Hann, Paul Irish, Peter Michaux and Justin
    Meyer for their previous work in this area.

    View Slide

  71. De ne what it means for a JavaScript application to be ‘large’.
    Challenge
    • It’s a very tricky question to get right
    • Even experienced JavaScript developers have
    trouble accurately de ning this

    View Slide

  72. I asked some intermediate developers what their thoughts on this were.
    Some Answers
    Umm..JavaScript apps with over
    100,000 lines of code?

    View Slide

  73. I asked some intermediate developers what their thoughts on this were.
    Some Answers
    Obviously, apps with over 1MB of
    JavaScript code written in-house!

    View Slide

  74. Large-scale JavaScript apps are non-trivial
    applications requiring signi cant developer effort
    to maintain, where most heavy lifting of data
    manipulation and display falls to the browser.
    My Answer

    View Slide

  75. Google’s GMail
    Some Examples

    View Slide

  76. The Yahoo! Homepage
    Some Examples

    View Slide

  77. AOL Mail / Phoenix
    Some Examples

    View Slide

  78. If working on a signi cantly large JavaScript app,
    remember to dedicate suf cient time to planning the
    underlying architecture that makes the most sense.
    It’s often more complex than we initially think.
    Current Architecture

    View Slide

  79. might contain a mixture of the following:
    Your Current Architecture
    MVC (Models/Views/Controllers)
    An Application Core
    Modules
    Custom Widgets
    JavaScript Libraries & Toolkits

    View Slide

  80. The last slide contains some great architectural components, but used non-
    optimally they can come with a few problems:
    Possible Problems
    How much of this is
    instantly re-usable?
    Can single modules
    exist on their own
    independently?
    Can single modules
    be tested
    independently?

    View Slide

  81. Some further concerns:
    Possible Problems
    How much do
    modules depend on
    others in the system?
    Is your application
    tightly coupled?
    If speci c parts of
    your app fail, can it
    still function?

    View Slide

  82. What future concerns haven’t been factored in to this architecture?
    Think Long-Term
    • You may decide to switch from using jQuery to Dojo
    or YUI for reasons of performance, security or design
    • Libraries are not easily interchangeable and have
    high switching costs if tightly coupled to your app

    View Slide

  83. Think long term - what future concerns
    haven’t been factored in yet?

    View Slide

  84. This is important.
    Ask Yourself
    If you reviewed your architecture right
    now, could a decision to switch
    libraries be made without rewriting
    your entire application?

    View Slide

  85. “The secret to building large apps is never build large
    apps. Break your applications into small pieces. Then,
    assemble those testable, bite-sized pieces into your big
    application”
    - Justin Meyer

    View Slide

  86. “The more tied components are to each other, the less
    reusable they will be, and the more dif cult it becomes to
    make changes to one without accidentally affecting
    another”
    - Rebecca Murphey

    View Slide

  87. “The key is to acknowledge from the start that you have no
    idea how this will grow.
    When you accept that you don't know everything, you
    begin to design the system defensively.”
    - Nicholas Zakas

    View Slide

  88. Fixing our architecture with what we’ve learned to date.
    Solution: Combine Patterns
    “The only difference between a problem and a solution is that people understand the
    solution.’
    - Charles F. Kettering

    View Slide

  89. We’re going to build something special.
    Let’s Combine Our Patterns
    Module Pattern
    Facade Pattern
    Mediator Pattern
    +
    +
    = WIN

    View Slide

  90. What do we want?
    Brainstorm.
    Loosely coupled
    architecture
    Functionality broken
    down into smaller
    independent modules
    Framework or library
    agnostic. Flexibility to
    change in future.

    View Slide

  91. How might we achieve this?
    Some More Ideas.
    Single modules speak
    to the app when
    something interesting
    happens
    An intermediate layer
    interprets requests.
    Modules don’t access
    the core or libraries
    directly.
    Prevent apps from falling
    over due to errors with
    speci c modules.

    View Slide

  92. The Facade pattern will play the role of:
    The Facade
    • An abstraction of the application core that sits in
    the middle between it and modules
    • Ensures a consistent interface to our modules is
    available at all times
    • Should be the only thing modules are aware of -
    they shouldn’t know about other components

    View Slide

  93. How else can it help?
    The Facade
    • Components communicate via the facade so it
    needs to be dependable
    • It acts as a security guard, determining which
    parts of the application a module can access
    • Components only call their own methods or
    methods from a sandbox, but nothing they don’t
    have permission to

    View Slide

  94. This is how modules might normally communicate with the mediator.
    The Facade

    View Slide

  95. This is where the Facade ts in. The intermediate security layer that pipes noti cations back to the
    mediator for processing.
    The Facade

    View Slide

  96. The Facade
    An abstraction of the core, it listens out for interesting
    events and says ‘Great. What happened? Give me the
    details’.

    View Slide

  97. The Facade
    It also acts as a permissions manager. Modules only
    communicate through this and are only able to do what
    they’ve been permitted to.

    View Slide

  98. A Quick Note:
    • Nicholas Zakas refers to the facade as a sandbox
    controller
    • Agrees it could equally be considered the adapter,
    proxy or facade pattern
    • I prefer ‘facade’ as it matches the purpose most
    closely

    View Slide

  99. The Mediator Pattern
    The Application Core
    • It’s job is to manage the module lifecycle
    • When is it safe for a module to start?
    • When should it stop?
    • Modules should execute automatically when
    started

    View Slide

  100. The Mediator Pattern
    The Application Core
    • It’s not the core’s job to decide whether this
    should be when the DOM is ready.
    • The core should enable adding or removing
    modules without breaking anything.
    • It should ideally also handle detecting and
    managing errors in the system.

    View Slide

  101. The core acts as a 'Pub/Sub' manager using the mediator pattern
    The Application Core

    View Slide

  102. The Application Core
    Manages the module lifecycle. It reacts to events passed
    from the facade and starts, stops or restarts modules as
    necessary. Modules here automatically execute when
    loaded.

    View Slide

  103. Tying in modules into the architecture
    Modules
    • Modules want to inform the application when
    something interesting happens. e.g. a new
    message has arrived
    • Correctly publishing events of interest should be
    their primary concern

    View Slide

  104. Tying in modules into the architecture
    Modules
    • Modules should ideally not be concerned about:
    • what objects or modules are being noti ed
    • where these objects are based (client? server?)
    • how many objects subscribe to noti cations

    View Slide

  105. Modules contain speci c pieces of functionality for your application. They publish noti cations
    informing the application whenever something interesting happens
    Modules

    View Slide

  106. Tying in modules into the architecture
    Modules
    • They also shouldn’t be concerned with what
    happens if other modules in the system fail to
    work
    • Leave this up to the mediator

    View Slide

  107. If a single module fails, the facade and mediator should stop and restart it.
    Modules

    View Slide

  108. Modules
    Unique blocks of functionality for your application. They
    inform the application when something interesting
    happens. Don’t talk to each other directly, only concerned
    with publishing events of interest.

    View Slide

  109. Live demo 1: Backbone.js + RequireJS +
    AMD modules + mediator pattern
    https://github.com/addyosmani/backbone-aura

    View Slide

  110. Enough talk! Let’s take a look at some real code.
    Aura: A Preview
    Aura is a framework I’m building at AOL that provides a boilerplate for one way to approach
    implementing this architecture. It will be released for open-source consumption once stable.

    View Slide

  111. The Mediator / Application Core
    Aura: Core
    • Swappable Mediator with a light wrapper around a
    speci c JavaScript library
    • Ability to start and stop modules
    • By default it comes with wrappers for both Dojo
    and jQuery, with core syntax that resembles the
    latter

    View Slide

  112. How does this work?
    Aura: Core
    • Accessing this wrapper, the facade doesn’t care
    what framework has been slotted in. It works with
    the abstraction
    • Behind the scenes, arguments are mapped to the
    relevant jQuery or dojo methods and signatures for
    achieving speci c behaviour

    View Slide

  113. A sample of the method signatures and namespaces supported
    Aura: Core
    // some core methods for module management
    core.define(module_id, module_definition); // define a new module
    core.start(module_id); // initialise a module
    core.startAll(); // initialise all modules
    core.stop(module_id); // stop a specific module
    core.stopAll(); // stop all modules
    core.destroy(module_id); // destroy a specific module
    core.destroyAll(); // destroy all modules
    // core namespaces available out of the box
    core.events // bind, unbind etc.
    core.utils // type checking, module extension
    core.dom // DOM manipulation, CSS Styling

    View Slide

  114. Chaining and CSS Style Manipulation are both supported.
    Aura: Core.dom > CSS Styling, Chaining
    // Chaining and CSS style manipulation
    aura.core.dom.query('body').css({'background':'#1c1c1c'});
    aura.core.dom.query('#search_input').css({'background':'blue'}).css({'color':'pink'});
    aura.core.dom.query('#search_button').css({'width':'200','height':'100'});
    // Manipulating styles within a context
    aura.core.dom.css('body', {'background':'red'});
    aura.core.dom.css('#shopping-cart',{'color':'green','background':'yellow'});
    aura.core.dom.css('#product-panel li', {'background':'purple'});
    // Passing in DOM nodes also works
    var test = aura.core.dom.query('#shopping-cart'); //.query should handle this.
    aura.core.dom.css(test, {'background':'purple'});

    View Slide

  115. Aura: Core.dom > CSS Styling, Chaining
    // Chaining and CSS style manipulation
    aura.core.dom.query('body').css({'background':'#1c1c1c'});
    aura.core.dom.query('#search_input').css({'background':'blue'}).css({'color':'pink'});
    aura.core.dom.query('#search_button').css({'width':'200','height':'100'});
    // Manipulating styles within a context
    aura.core.dom.css('body', {'background':'red'});
    aura.core.dom.css('#shopping-cart',{'color':'green','background':'yellow'});
    aura.core.dom.css('#product-panel li', {'background':'purple'});
    // Passing in DOM nodes also works
    var test = aura.core.dom.query('#shopping-cart'); //.query should handle this.
    aura.core.dom.css(test, {'background':'purple'});
    Look familiar? In my case I’ve modelled my abstraction around the jQuery API. Behind the
    scenes, this works with both jQuery and Dojo, providing a single abstraction.

    View Slide

  116. Attribute manipulation and animation are also abstracted using an API similar to jQuery.
    Remember, with Dojo this actually maps arguments back to the relevant Dojo methods needed
    to achieve the task.
    Aura: Core.dom > Attribs, Anim
    // Get and set attributes
    console.log(aura.core.dom.query('#seach_input').attr('title','foobar'));
    console.log(aura.core.dom.query('#search_input').attr('title'));
    // Passing in DOM nodes
    var q = aura.core.dom.query('#shopping-cart');
    console.log(aura.core.dom.attr(q, 'id'));
    // Animation support
    aura.core.dom.animate('#product-panel li', { width: 400, height:20}, 5000);
    aura.core.dom.animate('button', {width: 200, duration: 100});
    aura.core.dom.animate('p', {width:20, height:40, padding:10,duration:200});

    View Slide

  117. Similarly, element creation and ajax are also supported in the abstracted core interface.
    Aura: Core.dom > Create, Ajax
    // Element creation
    var el = aura.core.dom.create("a", {
    href: "foo.html",
    title: "bar!",
    innerHTML: "link"
    },
    'body');
    // XHR/Ajax requests (deferred support coming soon)
    aura.core.dom.ajax({
    url:'index.html',
    type:'get', //post, put
    dataType: "text",
    success:function(data){
    console.log('success');
    },
    error:function(){
    console.log('error');
    }
    });

    View Slide

  118. Live demo 2: Aura preview.

    View Slide

  119. Let’s review what we looked at today.
    What We Learned
    ‘Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps
    learning stays young. The greatest thing in life is to keep your mind young’
    - Henry Ford

    View Slide

  120. We looked at design patterns, jQuery &
    MVC, JavaScript patterns and how to
    nally build a large, scalable app.

    View Slide

  121. We looked at design patterns, jQuery &
    MVC, JavaScript patterns and how to
    nally build a large, scalable app.

    View Slide

  122. We looked at design patterns, jQuery &
    MVC, JavaScript patterns and how to
    nally build a large, scalable app.

    View Slide

  123. We looked at design patterns, jQuery &
    MVC, JavaScript patterns and how to
    nally build a large, scalable app.

    View Slide

  124. Large-scale apps: Three design patterns to create scalable ‘future-proof’
    application architectures. The idea is to have:
    Summary
    Application core
    Mediator
    Module manager
    Swappable
    Facade
    Core abstraction
    Permission manager
    Modules
    Highly decoupled
    Unique blocks
    (Optionally) Framework
    agnostic

    View Slide

  125. This can be very useful as:
    Summary
    • Modules are no longer dependent on anyone
    • They can be managed so that the application
    doesn’t (or shouldn’t) fall over.
    • You can theoretically pick up any module, drop it
    in a page and start using it in another project

    View Slide

  126. I’ve written about some of these topics in more depth:
    Further Reading
    • Writing Modular JavaScript with AMD, CommonJS
    & ES Harmony http://addyosmani.com/writing-modular-js
    • Patterns For Large-scale JavaScript Application
    Architecture http://addyosmani.com/largescalejavascript/
    • Essential jQuery Plugin Patterns http://
    coding.smashingmagazine.com/2011/10/11/essential-jquery-plugin-patterns/
    • Building Large-Scale jQuery Applications http://
    addyosmani.com/blog/large-scale-jquery/

    View Slide

  127. View Slide

  128. For more on this architecture and other topics, check out:
    That’s it.
    Blog
    Twitter
    GitHub
    http://addyosmani.com
    @addyosmani or @addy_osmani
    http://github.com/addyosmani

    View Slide