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.
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
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?
5. What is a ‘large’ application?
“A non-trivial application
requiring significant developer
effort to maintain”
Correct.
11. Your Architecture
Your current architecture likely resembles a mixture of the following:
Custom Widgets
Modules
Application Core
MVC (Models/Views/Controllers)
JavaScript Libraries & Toolkits
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?
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?
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?
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?
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?
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.
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.
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.
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.
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.
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
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.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
40. Revised Architecture
• Your new architecture could potentially look something like this:
Publishers
Libraries Self-contained modules
Adapter (abstraction of the core) Mediation
Subscribers
Application Core (Mediator)
tied into MVC if using that
pattern.
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.
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’.
43. Tying in: the core
The core will then react/start or stop other modules
related as necessary.
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
45. Module Communication
‘Tom’s order has been
successfully packaged
Module 1
OrderPackager
Adapter
notify(‘orderPackaged’,‘Tom’,‘success’) M
Start LabelManager
Core
Module 2
LabelManager ‘Tom’s order has been
labelled
notify(‘orderLabelled’,‘Tom’, ‘success’)
Start DispatchManager
Module 3
DispatchManager ‘Tom’s order has been
dispatched
notify(‘orderDispatched’,‘Tom’, ‘success’,’12-08-11’)
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.
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.
48. Result
Modules can be easily tested and maintained on
their own.
Modules can be added or removed without the
application falling over.