Coupling is when two (or more) pieces of code must know each other in order to function correctly. We consider this bad when this relationship is unnecessary.
Decoupling is when we remove these unnecessary relationships, allowing units of code to function independently or free of dependencies they don’t need to be directly tied to.
USE CLOSURE/GWT IF POSSIBLE OR BORROW SOME OF THESE IDEAS TO WORK WITH YOUR OWN STACK IF YOU’RE NOT READY. (AND MAYBE TRY OUT SOME OTHER AWESOME ONES TOO)
ALLOW YOU TO CONTROL THE LIFECYCLE OF YOUR WIDGETS? MAXIMIZE THE REUSABILITY OF COMPONENTS AND WIDGETS? ALLOW YOU TO EASILY SWITCH LIBRARIES YOU USE WITHOUT MASSIVE CODE RE-WRITES? STILL WORK IF A SPECIFIC MODULE FAILS?
JQUERY: COUPLED, DIRECT CALLS $.when( $.ajax("WebRebels/mail.php") ) .then(function( ajaxArgs ){ var jqXHR = ajaxArgs[2], data = jqXHR.responseText; // Now has to worry about all of these next... // Display notification and preview modals.show('New Message', data); // Play new message sound audioManager.play('newMessage'); // Update the unread message count messages.increaseMessageCount('unread'); });
JQUERY: DECOUPLED, PUBLISH/SUBSCRIBE // Dialogs $.subscribe('newMessage', function(){ modals.show('New Message', data); }); // Sounds $.subscribe('newMessage', function(){ audioManager.play('newMessage'); }); $.when( $.ajax("WebRebels/mail.php") ) .then(function( ajaxArgs ){ var jqXHR = ajaxArgs[2], data = jqXHR.responseText; // Tell the application there is a new message, share the data $.publish('newMessage', data); // Other modules can now just listen out for 'newMessage' });
PUB/SUB WITH RADIO.JS myFunction = function(){ /*...*/ } // create topic called newMessage and subscribe myFunction radio('newMessage').subscribe(myFunction); // publish to the topic newMesage radio('newMessage').broadcast(data); // unsubscribe myFunction from the topic newMessage radio('newMessage').unsubscribe(myFunction); // do all of the above in one line via chaining radio('newMessage') .subscribe(myFunction) .broadcast(data) .unsubscribe(myFunction);
PUB/SUB IN NODE WITH FAYE var Faye = require('faye'), server = new Faye.NodeAdapter({mount: '/'}); server.listen(8000); // Create a client var client = new Faye.Client('http://localhost:8000/'); // Define subscribers client.subscribe('/messages', function(message) { alert('Got a message: ' + message.text); }); // Publish messages client.publish('/messages', { text: 'Hello Web Rebels!' });
A SIMPLE FACADE W/ THE MODULE PATTERN var module = (function() { var myPrivates = { i:5, get : function() { console.log('current value:' + this.i); }, set : function( val ) { this.i = val; }, run : function() { console.log('running'); } }; return { facade : function( args ) { myPrivates.set(args.val); myPrivates.get(); if ( args.run ) { myPrivates.run(); } } } }()); Badly named, but all of this is private. This facade is all the public interact with. It’s a limited API that takes input like the below and does more work behind the scenes. module.facade({run: true, val:10}); // outputs current value: 10, running
JQUERY’S $(document).ready(..) // We just use this.. $(document).ready(...) or // But its a lot more complex than that (this only reflects half of what it does), but the beauty is that we don’t need to worry about the implementation-level details. (function (window) { // Define a local copy of $ var $ = function (callback) { readyBound = false; $.isReady = false; if (typeof callback == 'function') { DOMReadyCallback = callback; } bindReady(); }, // Use the correct document accordingly with window argument (sandbox) document = window.document, readyBound = false, DOMReadyCallback = function () {}, // The ready event handler DOMContentLoaded; // Is the DOM ready to be used? Set to true once it occurs. $.isReady = false; // Handle when the DOM is ready var DOMReady = function () { // Make sure that the DOM is not already loaded if (!$.isReady) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if (!document.body) { setTimeout(DOMReady, 13); return; } // Remember that the DOM is ready
TOWER HANDLES WHAT PLANES CAN TAKE OFF OR LAND ALL COMMUNICATION DONE FROM PLANES TO TOWER, NOT PLANE TO PLANE A CENTRALISED CONTROLLER IS KEY TO SUCCESS HERE ANALOGY: AIR TRAFFIC CONTROL
Mediator.js - solid mediator implementation // We just use this.. $(document).ready(...) or // But its a lot more complex than that (this only reflects half of what it does), but the beauty is that we don’t need to worry about the implementation-level details. (function (window) { // Define a local copy of $ var $ = function (callback) { readyBound = false; $.isReady = false; if (typeof callback == 'function') { DOMReadyCallback = callback; } bindReady(); }, // Use the correct document accordingly with window argument (sandbox) document = window.document, readyBound = false, DOMReadyCallback = function () {}, // The ready event handler DOMContentLoaded; // Is the DOM ready to be used? Set to true once it occurs. $.isReady = false; // Handle when the DOM is ready var DOMReady = function () { // Make sure that the DOM is not already loaded if (!$.isReady) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if (!document.body) { setTimeout(DOMReady, 13); return; } // Remember that the DOM is ready http://thejacklawson.com/ Mediator.js/ http://thejacklawson.com/Mediator.js/
Simple AMD Module // Call define() with an optional ID, a dependency array and a factory function allowing us to alias dependencies loaded for usage define(optionalId, ['underscore', 'backbone'], function (_, Backbone) { // Return a defined module return function () {}; });
CommonJS: require() and exports // package/lib is a dependency we require var lib = require('package/lib'); // some behaviour for our module function foo(){ lib.log('hello world!'); } // export (expose) foo to other modules exports.foo = foo;