Scalable Javascript Application Architecture: Nicholas C. Zakas - @slicknet
Scalable Javascript Application Architecture: Nicholas C. Zakas - @slicknet
View Controller
Single-page apps
&
Multi-page apps
Building an application
framework
An application framework
is like a playground for your code
Provides structure around otherwise unrelated activities
flickr.com/photos/osterwalder/152697503/
Isn't that what JavaScript
libraries do?
flickr.com/photos/skistz/398429879/
Base Library
Module Theory
Everything is a module
module (n)
1 : a standard or unit of measurement
2 : the size of some one part taken as a unit of measure by which the
proportions of an architectural composition are regulated
3 a : any in a series of standardized units for use together: as (1) : a
unit of furniture or architecture (2) : an educational unit which covers
a single subject or topic b : a usually packaged functional assembly
of electronic components for use with other such assemblies
4 : an independently operable unit that is a part of the total structure
of a space vehicle
5 a : a subset of an additive group that is also a group under addition
b : a mathematical set that is a commutative group under addition
and that is closed under multiplication which is distributive from the
left or right or both by elements of a ring and for which a(bx) = (ab)x
or (xb)a = x(ba) or both where a and b are elements of the ring and x
belongs to the set
Source: Me
Web application modules consist of
HTML + CSS + JavaScript
Any single module should be able
to live on its own
Loose coupling allows you to make changes to
one module without affecting the others
flickr.com/photos/quinnanya/3575417671/
flickr.com/photos/renfield/3414246938/
Application
Core
Base Library
Application Architecture
Modules
Sandbox
Application Core
Base Library
Module
Module Module
return {
init: function(){
//constructor
},
destroy: function(){
//destructor
}
};
});
Which parts know about the web
application being built?
None of them
Each part of the architecture is like a puzzle piece
No single piece needs to know what the picture is
All that matters is that the piece does its own job correctly
flickr.com/photos/generated/501445202/
What is a module's job?
Hello, I'm the weather module.
It's my job to tell you the weather.
Hello, I'm the stocks module.
It's my job to tell you about the
stock market.
Each module's job is to create a
meaningful user experience
flickr.com/photos/eljay/2392332379/
flickr.com/photos/madaise/3406217980/
Application Architecture
Modules
Sandbox
Application Core
Base Library
Module
Module Module
Application
Core
Base Library
Sandbox
Application
Core
Base Library
Module
Module Module
flickr.com/photos/heraklit/169566548/
Core.register("module-name", function(sandbox){
return {
init: function(){
destroy: function(){
//destructor
}
};
});
Sandbox Jobs
• Consistency
• Security
• Communication
Take the time to design the
correct sandbox interface
It can't change later
Application Architecture
Modules
Sandbox
Application Core
Base Library
Module
Module Module
Application
Core
Base Library
Application
Core
return {
register: function(moduleId, creator){
moduleData[moduleId] = {
creator: creator,
instance: null
};
},
start: function(moduleId){
moduleData[moduleId].instance =
moduleData[moduleId].creator(new Sandbox(this));
moduleData[moduleId].instance.init();
},
stop: function(moduleId){
var data = moduleData[moduleId];
if (data.instance){
data.instance.destroy();
data.instance = null;
}
}
}
}();
Core = function(){
return {
//more code here...
startAll: function(){
for (var moduleId in moduleData){
if (moduleData.hasOwnProperty(moduleId)){
this.start(moduleId);
}
}
},
stopAll: function(){
for (var moduleId in moduleData){
if (moduleData.hasOwnProperty(moduleId)){
this.stop(moduleId);
}
}
},
flickr.com/photos/markhillary/353738538/
TimelineFilter = {
changeFilter: function(filter){
Timeline.applyFilter(filter);
}
}; Tight
Coupling
StatusPoster = {
postStatus: function(status){
Timeline.post(status);
}
}; Tight
Coupling
Timeline = {
applyFilter: function(filter){
//implementation
},
post: function(status){
//implementation
}
};
Core.register("timeline-filter", function(sandbox){
return {
changeFilter: function(filter){
sandbox.notify({
type: "timeline-filter-change",
data: filter
}); Loose
}
}; Coupling
});
Core.register("status-poster", function(sandbox){
return {
postStatus: function(statusText){
sandbox.notify({
type: "new-status",
data: statusText
}); Loose
}
};
Coupling
});
Core.register("timeline", function(sandbox){
return {
init: function(){
sandbox.listen([
"timeline-filter-change",
"post-status"
], this.handleNotification, this); Loose
}, Coupling
handleNotification: function(note){
switch(note.type){
case "timeline-filter-change":
this.applyFilter(note.data);
return;
case "post-status":
this.post(note.data);
return;
}
}
};
});
When modules are loosely coupled,
removing a module doesn't break the others
No direct access to another module = no breaking should the module disappear
The application core handles errors
Uses available information to determine best course of action
flickr.com/photos/brandonschauer/3168761995/
Core = function(){
function createInstance(moduleId){
var instance =
moduleData[moduleId].creator(new Sandbox(this)),
name, method;
if (!debug){
for (name in instance){
method = instance[name];
if (typeof method == "function"){
instance[name] = function(name, method){
return function(){
try { return method.apply(this, arguments);}
catch(ex) {log(1, name + "(): " + ex.message);}
};
}(name, method);
}
}
}
return instance;
}
}();
Learn more
http://www.slideshare.net/nzakas/enterprise-javascript-error-handling-presentation
Application Core Jobs
• Manage module lifecycle
• Enable inter-module communication
• General error handling
• Be extensible
Why not?
Web applications change
Often in ways that you couldn't possibly anticipate
Plan for extension
flickr.com/photos/pointnshoot/1443575327/
Application
Extension Extension
Core
Base Library
What Extensions?
• Error handling
• Ajax communication
• New module capabilities
• General utilities
• Anything!
Ajax communication comes in different forms
Tends to be tied to something available on the server
Request format Entrypoint
Response format
Application
Extension Ajax/XML
Core
Base Library
GET ?name=value&name=value /ajax
Request format Entrypoint
Response format
<response>
<status>ok|error</status>
<data>
<results>
<result name="..." />
<result name="..." />
</results>
</data>
</response>
Entrypoint
var xhr = new XMLHttpRequest();
xhr.open("get", "/ajax?name=value", true);
Request
xhr.onreadystatechange = function(){ format
if (xhr.readyState == 4){
if (xhr.status == 200 || xhr.status == 304){
var statusNode = xhr.responseXML.getElementsByTagName("status")[0],
dataNode = xhr.responseXML.getElementsByTagName("data")[0];
if (statusNode.firstChild.nodeValue == "ok"){
handleSuccess(processData(dataNode));
} else { Response
handleFailure(); format
}
} else {
handleFailure();
}
}
};
xhr.send(null);
Basic implementation
Lowest-level Ajax with XMLHttpRequest
Library
reference Entrypoint
var id = Y.io("/ajax?name=value", {
method: "get", Request
on: { format
success: function(req){
var statusNode = req.responseXML.getElementsByTagName("status")[0],
dataNode = req.responseXML.getElementsByTagName("data")[0];
if (statusNode.firstChild.nodeValue == "ok"){
handleSuccess(processData(dataNode));
} else { Response
handleFailure(); format
}
},
failure: function(req){
handleFailure();
}
}
});
Response format
Response format
{
status: "ok|error",
data: {
results: [
"...",
"..."
]
}
}
Module
Module Module
Application
Extension Ajax/JSON
Core
Base Library
Ajax Extension Jobs
• Hide Ajax communication details
• Provide common request interface
• Provide common response interface
• Manage server failures
Application Architecture
Modules
Sandbox
Application Core
Base Library
Module
Module Module
Application
Extension Extension
Core
Base Library
The base library provides basic functionality
Ironic, huh?
Base Library
flickr.com/photos/kartik_m/2724121901/
Application
Core
Dojo
Module
Module Module
Application
Core
YUI
Base Library Jobs
• Browser normalization
• General-purpose utilities
Parsers/serializers for XML, JSON, etc.
Object manipulation
DOM manipulation
Ajax communication
• Provide low-level extensibility
Module
Module Module
Application
Extension Extension
Core
Application
Extension Extension
Core
Base Library
Only the application core knows which
base library is being used
No other part of the architecture should need to know
Application
Core
Base Library
Sandbox
Application
Core
Application
Extension Extension
Core
flickr.com/photos/misocrazy/151021636/
A scalable JavaScript architecture
allows you to replace any block
without fear of toppling the tower
flickr.com/photos/aku-ma/2424194422/
The End
Etcetera
•My blog: www.nczonline.net
•Twitter: @slicknet
•These Slides: slideshare.net/nzakas