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

Large-Scale JavaScript Development

Addy Osmani
October 29, 2011

Large-Scale JavaScript Development

In this talk, I present a number of useful patterns for developing large-scale JavaScript applications that are highly decoupled.

Addy Osmani

October 29, 2011
Tweet

More Decks by Addy Osmani

Other Decks in Technology

Transcript

  1. View Slide

  2. Introduction
    This talk will cover strategies that can help
    streamline your application architecture.
    Thanks to Nicholas Zakas, Rebecca
    Murphey, Paul Irish and Justin Meyer for their
    previous work in this area.

    View Slide

  3. What is a ‘large’ application?
    Some developers suggested:
    “Apps where the size of code is
    over over 100,000 LOC”
    Incorrect, because code size does
    not always correlate to complexity

    View Slide

  4. What is a ‘large’ application?
    “Apps with over 1MB of JS code
    written in-house”
    Again, this could be very simplistic
    code. Can we get more clear?

    View Slide

  5. What is a ‘large’ application?
    “A non-trivial application
    requiring significant developer
    effort to maintain”
    Correct.

    View Slide

  6. SOME EXAMPLES
    GMail

    View Slide

  7. SOME EXAMPLES
    Yahoo! Homepage

    View Slide

  8. SOME EXAMPLES
    MobileMe

    View Slide

  9. SOME EXAMPLES
    Aol Mail / Phoenix

    View Slide

  10. View Slide

  11. Your Architecture
    MVC (Models/Views/Controllers)
    Application Core
    Modules
    Custom Widgets
    JavaScript Libraries & Toolkits
    Your current architecture likely resembles a mixture of the following:

    View Slide

  12. Possible problems with this:
    How much of this architecture is instantly re-usable?
    Can single modules exist on their own independently?
    Are they self-contained?

    View Slide

  13. Possible problems with this:
    How much do modules depend on other modules
    inside the same system?
    Does your app contain many modules that are tightly
    coupled?

    View Slide

  14. Possible problems with this:
    How easily can you test individual modules?
    How certain are you that if specific parts of your
    application fail, it can still function?

    View Slide

  15. Think long-term
    Developers often couple their DOM manipulation code
    quite tightly with the rest of their application
    Why is this not a good idea if we’re thinking long-term?

    View Slide

  16. Think long-term
    You may decide to switch from using jQuery to Dojo or
    YUI for reasons of performance, security or design.
    Can this decision currently be made without rewriting
    your entire application?

    View Slide

  17. Remember..
    “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

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

    View Slide

  19. Let’s brainstorm.
    We want a loosely coupled architecture with
    functionality broken down into smaller modules that
    aren’t dependant on one another.
    You probably already use modules but we need them
    to be fully independent entities.

    View Slide

  20. Some more ideas.
    To achieve this we need single modules to speak to
    the rest of the application when something interesting
    happens.
    We then use a different layer to interpret requests so
    that modules don’t directly access the core.
    This aids in preventing applications from falling over
    due to errors with a specific module.

    View Slide

  21. and wrapping up..
    Modules shouldn’t be able to access everything.
    They probably can in most current architectures.
    Having an intermediate layer handle permissions for
    which modules can access which parts of your
    framework gives you a layer of security.
    This means a module is only able to do at most what
    we’ve permitted it do.

    View Slide

  22. Solution
    Module theory +
    Facade pattern +
    Mediator pattern
    = WIN

    View Slide

  23. Module Theory
    “Anything can be defined as a reusable module”
    - Zakas.
    Modules should be considered independent units
    of functionality that can exist on their own

    View Slide

  24. Module Theory
    Modules have very limited knowledge of what’s
    going on in the rest of the application
    Loose coupling is essential to this - modules
    should ideally not depend on other modules.

    View Slide

  25. Loose Coupling
    Facilitates improved maintainability by removing code
    dependencies where possible
    In our case, modules should not rely on other modules
    in order to function correctly.
    When used effectively, it’s straight-forward to see
    how changes to one part of a system may affect
    another.

    View Slide

  26. Applying Module Theory
    Any significantly non-trivial application should be built
    from modular components
    When a module is reusable it’s clear how to use or
    extend it
    In JavaScript, there are several options for defining
    modules, including:

    View Slide

  27. The Module Pattern
    The well-known module pattern makes use of
    closures to bake privacy, state and organization into
    your objects.
    It’s quite similar to an IIFE with an object returned
    instead of a function.
    Commonly implemented as a singleton.

    View Slide

  28. Object Literals
    Object literal notation is another option for
    structuring modules
    Basically consists of an array of key:value pairs
    Methods defined using object literal notation don’t exist
    until the execution of the script.

    View Slide

  29. Facade Pattern
    Provides a convenient higher-level interface to a
    larger body of code, regardless of underlying
    complexity
    Hides the inner-workings of a library or set of
    modules, allowing the implementation to be less
    important.
    We thus only need to interact with the facade
    rather than the subsystem it encompasses.

    View Slide

  30. The Mediator Pattern
    Encapsulates how disparate modules interact with
    each other by acting as an intermediary
    Promotes loose coupling by preventing objects from
    referring to each other explicitly, solving our module
    inter-dependency issues.

    View Slide

  31. The Mediator Pattern
    Allows for actions of each module to vary
    independently, so it’s extremely flexible
    Somewhat similar to Observer/Pub-Sub, so it’s not
    difficult to understand how it fits in if you’ve used one of
    these patterns previously.

    View Slide

  32. Why is it the bee’s knees?
    Allows modules to broadcast or listen for messages
    without worrying about the rest of the system
    Messages can be handled by any number of modules
    at once.
    Typically significantly more easy to add or remove
    features to systems which are loosely coupled like this.

    View Slide

  33. Mediator downsides
    By adding a mediator between modules, they must
    always communicate indirectly. This can cause a very
    minor performance drop.
    Because of the nature of loose coupling, it’s difficult to
    establish how a system might react by only looking at
    the broadcasts.
    At the end of the day, tight coupling causes all kinds of
    headaches and this is one solution.

    View Slide

  34. Mediator Metaphor
    Think of an airport control tower. The tower
    handles what planes can take off and land.
    All communications are done from the planes to
    the control tower, rather than from plane-to-
    plane
    A centralised controller is key to the success of
    this system as is the case with the mediator
    pattern.

    View Slide

  35. The Facade
    Effectively, 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

  36. The Facade
    Components communicate via the adapter so it needs
    to be dependable
    The adapter acts as a security guard, determining
    which parts of the application a module can access
    Components only call their own methods and
    shouldn’t interact with anything they don’t have
    permission to

    View Slide

  37. NOTE:
    Nicholas Zakas refers to the facade here as a sandbox
    controller.
    Agrees that it could equally be considered the adapter,
    proxy or facade pattern.
    As Stoyan Stefanov defined an existing ‘sandbox’
    pattern, I refer to the sandbox as a facade as IMO this
    pattern matches it’s purpose most closely.

    View Slide

  38. 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

  39. 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

  40. Revised Architecture
    Application Core (Mediator)
    tied into MVC if using that
    pattern.
    Self-contained modules
    Libraries
    • Your new architecture could potentially look something like this:
    Adapter (abstraction of the core)
    Mediation
    Publishers
    Subscribers

    View Slide

  41. Tying in: modules
    Modules want to inform the application when
    something interesting happens. eg. a new message
    has arrived.other modules related as necessary.
    Correctly publishing events of interest should be their
    primary concern.

    View Slide

  42. Tying in: the facade
    The core (via the abstracted adapter) listens out for
    interesting events and says ‘Awesome. What
    happened? Give me the details’.

    View Slide

  43. Tying in: the core
    The core will then react/start or stop other modules
    related as necessary.

    View Slide

  44. Modules
    Should ideally not be concerned about:
    what objects or modules are being notified
    where these objects are based (client? server?)
    how many objects subscribe to notification

    View Slide

  45. Module Communication
    Core
    Module 1
    OrderPackager
    Adapter
    M
    Module 2
    LabelManager
    ‘Tom’s order has been
    successfully packaged
    ‘Tom’s order has been
    labelled
    notify(‘orderPackaged’,‘Tom’,‘success’)
    notify(‘orderLabelled’,‘Tom’, ‘success’)
    Module 3
    DispatchManager ‘Tom’s order has been
    dispatched
    notify(‘orderDispatched’,‘Tom’, ‘success’,’12-08-11’)
    Start LabelManager
    Start DispatchManager

    View Slide

  46. Summary
    The core acts as like a ‘Pub/Sub’ manager using
    the mediator pattern. Responsible for module
    management.
    The facade abstracts the core to avoid modules
    touching it directly. Handles security.
    The modules contain specific pieces of
    functionality for your application.

    View Slide

  47. Result
    Modules are no longer dependent on anyone.
    If you stick to a consistent API, you can easily replace
    a module using jQuery with one using dojo later on.

    View Slide

  48. Result
    Modules can be easily tested and maintained on
    their own.
    Modules can be added or removed without the
    application falling over.

    View Slide