Large-Scale JavaScript Development

48
Addy Osmani

description

My talk from LondonJS

Transcript of Large-Scale JavaScript Development

Page 1: Large-Scale JavaScript Development

Addy Osmani

Page 2: Large-Scale JavaScript Development

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.

Page 3: Large-Scale JavaScript Development

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

Page 4: Large-Scale JavaScript Development

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?

Page 5: Large-Scale JavaScript Development

What is a ‘large’ application?

“A non-trivial application requiring significant developer effort to maintain”

Correct.

Page 6: Large-Scale JavaScript Development

SOME EXAMPLES

GMail

Page 7: Large-Scale JavaScript Development

SOME EXAMPLES

Yahoo! Homepage

Page 8: Large-Scale JavaScript Development

SOME EXAMPLES

MobileMe

Page 9: Large-Scale JavaScript Development

SOME EXAMPLES

Aol Mail / Phoenix

Page 10: Large-Scale JavaScript Development
Page 11: Large-Scale JavaScript Development

Your Architecture

MVC (Models/Views/Controllers)

Application Core

Modules

Custom Widgets

JavaScript Libraries & Toolkits

Your current architecture likely resembles a mixture of the following:

Page 12: Large-Scale JavaScript Development

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?

Page 13: Large-Scale JavaScript Development

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?

Page 14: Large-Scale JavaScript Development

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?

Page 15: Large-Scale JavaScript Development

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?

Page 16: Large-Scale JavaScript Development

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?

Page 17: Large-Scale JavaScript Development

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.

Page 18: Large-Scale JavaScript Development

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.

Page 19: Large-Scale JavaScript Development

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.

Page 20: Large-Scale JavaScript Development

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.

Page 21: Large-Scale JavaScript Development

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.

Page 22: Large-Scale JavaScript Development

Solution

Module theory +

Facade pattern +

Mediator pattern

= WIN

Page 23: Large-Scale JavaScript Development

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

Page 24: Large-Scale JavaScript Development

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.

Page 25: Large-Scale JavaScript Development

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.

Page 26: Large-Scale JavaScript Development

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:

Page 27: Large-Scale JavaScript Development

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.

Page 28: Large-Scale JavaScript Development

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.

Page 29: Large-Scale JavaScript Development

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.

Page 30: Large-Scale JavaScript Development

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.

Page 31: Large-Scale JavaScript Development

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.

Page 32: Large-Scale JavaScript Development

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.

Page 33: Large-Scale JavaScript Development

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.

Page 34: Large-Scale JavaScript Development

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.

Page 35: Large-Scale JavaScript Development

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.

Page 36: Large-Scale JavaScript Development

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

Page 37: Large-Scale JavaScript Development

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.

Page 38: Large-Scale JavaScript Development

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.

Page 39: Large-Scale JavaScript Development

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.

Page 40: Large-Scale JavaScript Development

Revised Architecture

Application Core (Mediator) tied into MVC if using that

pattern.

Self-contained modulesLibraries

• Your new architecture could potentially look something like this:

Adapter (abstraction of the core)Mediation

Publishers

Subscribers

Page 41: Large-Scale JavaScript Development

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.

Page 42: Large-Scale JavaScript Development

Tying in: the facade

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

Page 43: Large-Scale JavaScript Development

Tying in: the core

The core will then react/start or stop other modules related as necessary.

Page 44: Large-Scale JavaScript Development

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

Page 45: Large-Scale JavaScript Development

Module Communication

Core

Module 1OrderPackager

Adapter

M

Module 2LabelManager

‘Tom’s order has been successfully packaged

‘Tom’s order has been labelled

notify(‘orderPackaged’,‘Tom’,‘success’)

notify(‘orderLabelled’,‘Tom’, ‘success’)

Module 3DispatchManager ‘Tom’s order has been

dispatched

notify(‘orderDispatched’,‘Tom’, ‘success’,’12-08-11’)

Start LabelManager

Start DispatchManager

Page 46: Large-Scale JavaScript Development

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.

Page 47: Large-Scale JavaScript Development

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.

Page 48: Large-Scale JavaScript Development

Result

Modules can be easily tested and maintained on their own.

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