An update to the Scalable JavaScript presentation of 2009. Describes how to piece together a JavaScript application framework designed for maintainability.
5. An application framework
is like a playground for your code
Provides structure around otherwise unrelated activities
flickr.com/photos/osterwalder/152697503/
10. 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: Merriam-Webster Dictionary
11. 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: Merriam-Webster Dictionary
26. 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/
40. Module Rules
Hands to yourself
â Only call your own methods or those on the sandbox
â Don't access DOM elements outside of your box
â Don't access non-native global objects
Ask, don't take
â Anything else you need, ask the sandbox
Don't leave your toys around
â Don't create global objects
Don't talk to strangers
â Don't directly reference other modules
41. Modules must stay within their own sandboxes
No matter how restrictive or uncomfortable it may seem
flickr.com/photos/madaise/3406217980/
45. Module
Module Module
Module Sandbox Module
Modules only know the sandbox
The rest of the architecture doesn't exist to them
46. The sandbox also acts like a security guard
Knows what the modules are allowed to access and do on the framework
flickr.com/photos/heraklit/169566548/
48. Sandbox Jobs
Consistency
â Interface must be dependable
Security
â Determine which parts of the framework a module can
access
Communication
â Translate module requests into core actions
49. Take the time to design the
correct sandbox interface
It can't change later
53. The application core tells a module when
it should initialize and when it should shutdown
flickr.com/photos/bootbearwdc/20817093/
flickr.com/photos/bootbearwdc/20810695/
62. 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
63. The application core handles errors
Uses available information to determine best course of action
flickr.com/photos/brandonschauer/3168761995/
64. Core = function(){
var moduleData = {}, debug = false;
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;
}
//more code here
}();
66. Application Core Jobs
Manage module lifecycle
â Tell modules when to start and stop doing their job
Enable inter-module communication
â Allow loose coupling between modules that are related
to one another
General error handling
â Detect, trap, and report errors in the system
Be extensible
â The first three jobs are not enough!
70. flickr.com/photos/pointnshoot/1443575327/
Anything built for extension can never be
obsolete
Extensions augment the capabilities of the core to keep it relevant and useful
76. 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>
77. 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
78. 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();
}
}
});
Implementation using a library
Hides some of the ugliness but still tightly coupled to Ajax implementation
79. var id = sandbox.request({ name: "value" }, {
success: function(response){
handleSuccess(response.data);
},
failure: function(response){
handleFailure();
}
});
Implementation using sandbox
Passes through to core - hides all Ajax communication details
80. Request format Entrypoint
Response format
Ajax extension encapsulates all details
Any of these three can change without affecting modules
81. GET ?name=value&name=value /request
Request format Entrypoint
Response format
{
status: "ok|error",
data: {
results: [
"...",
"..."
]
}
}
83. Ajax Extension Jobs
Hide Ajax communication details
â Modules don't need to know any of it
Provide common request interface
â Modules use this interface to specify data to send to
the server
Provide common response interface
â Modules use this interface to retrieve data from the
response
Manage server failures
â Modules only care if they got what they wanted or
not, don't care why
93. Base Library Jobs
Browser normalization
â Abstract away differences in browsers with common
interface
General-purpose utilities
â Parsers/serializers for XML, JSON, etc.
â Object manipulation
â DOM manipulation
â Ajax communication
Provide low-level extensibility
97. Only the base library knows which browser
is being used
No other part of the architecture should need to know
Base Library
98. 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
99. Sandbox
Application
Core
Only the sandbox knows which application core
is being used
No other part of the architecture should need to know
100. Module
Module Module
Module Sandbox Module
The modules know nothing except that
the sandbox exists
They have no knowledge of one another or the rest of the architecture
101. Module
Module Module
Module Sandbox Module
Application
Extension Extension
Core
Extension Base Library Extension
No part knows about the web application
Over the past couple of years, we've seen JavaScript development earn recognition as a true discipline. The idea that you should architect your code, use patterns and good programming practices has really elevated the role of the front end engineer. In my opinion, part of this elevation has been the adoption of what has traditionally been considered back end methodologies. We now focus on performance and algorithms, there's unit testing for JavaScript, and so much more. One of the areas that I've seen a much slower than adoption that I'd like is in the area of error handling.How many people have an error handling strategy for their backend? How many have dashboards that display problems with uptime and performance? How many have anything similar for the front end?Typically, the front end has been this black hole of information. You may get a few customer reports here and there, but you have no information about what's going on, how often it's occurring, or how many people have been affected.
So what have we talked about? Maintainable JavaScript is made up of four components.First is Code Conventions that describe the format of the code youâre writing.Second is Loose Coupling â keeping HTML, JavaScript, and CSS on separate layers and keeping application logic out of event handlers.Third is Programming Practices that ensure your code is readable and easily debugged.Fourth is creating a Build Process