Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. 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.
  2. 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
  3. 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?
  4. Your Architecture MVC (Models/Views/Controllers) Application Core Modules Custom Widgets JavaScript

    Libraries & Toolkits Your current architecture likely resembles a mixture of the following:
  5. 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?
  6. 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?
  7. 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?
  8. 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?
  9. 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?
  10. 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.
  11. 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.
  12. 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.
  13. 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.
  14. 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.
  15. 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
  16. 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.
  17. 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.
  18. 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:
  19. 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.
  20. 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.
  21. 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.
  22. 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.
  23. 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.
  24. 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.
  25. 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.
  26. 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.
  27. 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.
  28. 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
  29. 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.
  30. 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.
  31. 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.
  32. 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
  33. 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.
  34. Tying in: the facade The core (via the abstracted adapter)

    listens out for interesting events and says ‘Awesome. What happened? Give me the details’.
  35. Tying in: the core The core will then react/start or

    stop other modules related as necessary.
  36. 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
  37. 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
  38. 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.
  39. 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.
  40. Result Modules can be easily tested and maintained on their

    own. Modules can be added or removed without the application falling over.