Slide 1

Slide 1 text

FEATURING ARTWORK FROM BRIAN O’MALLEY

Slide 2

Slide 2 text

I WORK AT AS A DEVELOPER PROGRAMS ENGINEER 50% ENGINEER 50% TECHNICAL WRITER WHO AM I?

Slide 3

Slide 3 text

When I tell people I work at Google they think my day is spent like this:

Slide 4

Slide 4 text

The reality is my days are mostly spent like this ; ) Bugs Bugs Bugs

Slide 5

Slide 5 text

I’M KIDDING OF COURSE! I love working for Google <3

Slide 6

Slide 6 text

I <333 WRITING

Slide 7

Slide 7 text

When I tell people I’m getting published, they think the quality of my books are like this:

Slide 8

Slide 8 text

The reality is the quality is a little more like this.

Slide 9

Slide 9 text

CONTRIBUTED TO: CREATED: TodoMVC jQuery UI Bootstrap jQuery Plugin Patterns Backbone Paginator Feature detection tests Documentation, Writing, Triage Latest Todo application

Slide 10

Slide 10 text

SO... DECOUPLING

Slide 11

Slide 11 text

DE..WHAT?

Slide 12

Slide 12 text

decoupling [ˌdiːˈkʌpəәngl] separating (joined or coupled subsystems) enabling them to exist and operate separately oooOoh.

Slide 13

Slide 13 text

Coupling

Slide 14

Slide 14 text

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.

Slide 15

Slide 15 text

decoupling

Slide 16

Slide 16 text

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.

Slide 17

Slide 17 text

BUT REALLY..DECOUPLING IS AMAZING.

Slide 18

Slide 18 text

SOME ARCHITECTURE IDEAS FROM GOOGLE PROJECTS. GUESS WHERE YOU’LL FIND DECOUPLING USED A LOT?

Slide 19

Slide 19 text

Use MVP as it supports decoupled development between multiple developers simultaneously Google Docs (GWT)

Slide 20

Slide 20 text

Applications should be able to function independently or with other apps in a container (think widgets) Google Docs (GWT)

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Many should be able to work on a codebase without being limited by dependencies Another Google project.

Slide 23

Slide 23 text

Use deferred JavaScript loading to only load chunks/modules as they're needed MUCH HARDER IF THEY’RE NOT DECOUPLED Old GMail, Google Docs

Slide 24

Slide 24 text

WE SEEM TO LIKE DECOUPLING.

Slide 25

Slide 25 text

GMail & Calendar: Closure AdWords & AdSense: Google Web Toolkit Google Docs/Drive : Closure + GWT BTW, in case you were wondering..we use

Slide 26

Slide 26 text

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)

Slide 27

Slide 27 text

DOES YOUR CURRENT ARCHITECTURE.. MODULES WIDGETS MVC LIBRARIES TOOLKITS APPLICATION CORE TEMPLATES

Slide 28

Slide 28 text

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?

Slide 29

Slide 29 text

I HOPE YOU SAID NO. LET’S CHANGE THAT!

Slide 30

Slide 30 text

DECOUPLING

Slide 31

Slide 31 text

COMPONENT-LEVEL DECOUPLING

Slide 32

Slide 32 text

CHARTS FORMULA EDITOR GRID SPREADSHEET WIDGET THEORETICAL EXAMPLE

Slide 33

Slide 33 text

TEXT FORMATTER TABLE AUTOCOMPLETE GRID SEARCH/FILTER REUSABLES

Slide 34

Slide 34 text

TEXT FORMATTER MEDIA MANAGER AUTOCOMPLETE STATUS UPDATE REUSABLES

Slide 35

Slide 35 text

PROMOTES REUSABILITY LESS COUPLING = EASIER REUSE

Slide 36

Slide 36 text

MODULE-LEVEL DECOUPLING BASIC CONCEPTS

Slide 37

Slide 37 text

LET’S GIVE DESIGN PATTERNS SOME LOVE

Slide 38

Slide 38 text

NOT THIS KIND OF LOVE.

Slide 39

Slide 39 text

OBSERVER (PUB/SUB) BASIC CONCEPTS

Slide 40

Slide 40 text

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'); });

Slide 41

Slide 41 text

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' });

Slide 42

Slide 42 text

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);

Slide 43

Slide 43 text

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!' });

Slide 44

Slide 44 text

OR WITH BACKBONE EVENTS var myObject = {}; _.extend( myObject, Backbone.Events ); // Subscribe myObject.on('eventName', function( msg ) { console.log( 'triggered:' + msg ); }); // Publish myObject.trigger('eventName', 'some event'); // You can even namespace: person.on('change:name change:age', function( msg ) { console.log('name and age changed'); });

Slide 45

Slide 45 text

LOGICALLY DECOUPLE OBJECTS GENERATING EVENTS FROM THOSE REACTING TO THEM NEW MESSAGE ‘HELLO WORLD’ THERE’S A NEW MESSAGE!

Slide 46

Slide 46 text

BAKED INTO MVC, MV* MODELS VIEWS CONTROLLERS MODELS CAN BE OBSERVED FOR CHANGES

Slide 47

Slide 47 text

FACADE PATTERN

Slide 48

Slide 48 text

HIDES IMPLEMENTATION LEVEL DETAILS FOR LIBRARIES

Slide 49

Slide 49 text

ENABLES COMPLEXITY BEHIND THE SCENES

Slide 50

Slide 50 text

$( el ).css() $( el ).animate(..) $( el ).attributes( key, value ) ... EXAMPLES YOU USE ALL THE TIME

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

MEDIATOR PATTERN

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

VERY SIMILAR TO..

Slide 56

Slide 56 text

ALLOWS MODULES TO BROADCAST OR LISTEN FOR NOTIFICATIONS A MEDIATOR:

Slide 57

Slide 57 text

MEDIATOR RESPONSIBLE FOR LETTING COLLEAGUES KNOW OF CHANGES. LIKE PUB/SUB, BUT: COLLEAGUES DON’T HAVE TO HOLD REFERENCES TO OTHER COLLEAGUES.

Slide 58

Slide 58 text

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/

Slide 59

Slide 59 text

Mediator.js function Subscriber(fn, options, context){ if (!this instanceof Subscriber) { return new Subscriber(fn, context, options); }else{ this.id = guidGenerator(); this.fn = fn; this.options = options; this.context = context; this.channel = null; } }; Publish: function(data){ for(var y = 0, x = this._callbacks.length; y < x; y++) { if(!this.stopped){ var callback = this._callbacks[y], l; if(callback.options !== undefined && typeof callback.options.predicate === "function"){ if(callback.options.predicate.apply(callback.context, data)){ callback.fn.apply(callback.context, data); } }else{ callback.fn.apply(callback.context, data); } } l = this._callbacks.length; if(l < x) y--; x = l; }

Slide 60

Slide 60 text

MODULES

Slide 61

Slide 61 text

MODULE PATTERN OBJECT LITERALS AMD ASYNCHRONOUS MODULES - UNTIL WE GET ES HARMONY SIMULATED PRIVACY MODULAR OBJECTS

Slide 62

Slide 62 text

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 () {}; });

Slide 63

Slide 63 text

AMD With Dynamic Dependencies define(function ( require ) { var isReady = false, foobar; // note the inline require within our module definition require(['foo', 'bar'], function (foo, bar) { isReady = true; foobar = foo() + bar(); }); // we can still return a module return { isReady: isReady, foobar: foobar }; });

Slide 64

Slide 64 text

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;

Slide 65

Slide 65 text

ECMAScript 6 Module /* * ES6 Modules (which you can use with Google Traceur) * http://traceur-compiler.googlecode.com/git/demo/repl.html */ module Profile { // module code export var firstName = 'Alex'; export var lastName = 'Russell'; export var year = 1973; } module ProfileView { import Profile.{firstName, lastName, year}; function setHeader(element) { element.textContent = firstName + ' ' + lastName; } // rest of module }

Slide 66

Slide 66 text

BRAINSTORM

Slide 67

Slide 67 text

LOOSELY COUPLED ARCHITECTURE CONTROLLABLE INDEPENDENT WIDGETS FLEXIBILITY TO CHANGE (E.G LIBRARIES) WHAT ARE WE LOOKING FOR?

Slide 68

Slide 68 text

NOTIFY US WHEN SOMETHING INTERESTING HAPPENS DON’T TOUCH ANYTHING THEY DON’T HAVE TO CAN’T CAUSE THE ENTIRE APP TO STOP WORKING WIDGETS

Slide 69

Slide 69 text

SOLUTION: COMBO! + +

Slide 70

Slide 70 text

APPLICATION CORE (MEDIATOR) WIDGETS (UI BLOCKS) MODULES (REQUIREJS 2.0 + AMD) SANDBOX (FACADE) AURA

Slide 71

Slide 71 text

DEMO

Slide 72

Slide 72 text

JUST VIEWING THE SLIDES? NO WORRIES! GRAB THE CODE BELOW. http://bit.ly/backbone-aura

Slide 73

Slide 73 text

1. THE APPLICATION CORE USING THE MEDIATOR PATTERN MANAGES THE WIDGET LIFECYCLE: STARTS, STOPS, RESTARTS IF NECESSARY

Slide 74

Slide 74 text

USING THE MEDIATOR PATTERN

Slide 75

Slide 75 text

Thanks RequireJS 2.0! shim config: no need to use patched Backbone.js or Underscore.js anymore! require.undef(): Unload specific modules

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

1. THE APPLICATION CORE USING THE MEDIATOR PATTERN REACTS TO ACTIONS PASSED BACK FROM A SANDBOX (FACADE) - HANDLES LOGIC

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

1. THE APPLICATION CORE USING THE MEDIATOR PATTERN HANDLES ERROR DETECTION AND MANAGEMENT

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

2. THE SANDBOX USING THE FACADE PATTERN AN ABSTRACTION OF THE CORE THAT’S AN API FOR COMMON TASKS, USED BY MODULES

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

2. THE SANDBOX USING THE FACADE PATTERN INTERFACE FOR ENSURING MODULES DON’T DIRECTLY ACCESS THE CORE/LIBRARIES

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

2. THE SANDBOX USING THE FACADE PATTERN PERMISSIONS MANAGER, SECURING WHAT MODULES CAN/CAN’T ACCESS

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

3. WIDGETS UNIQUE (INDEPENDENT) BLOCKS OF FUNCTIONALITY FOR YOUR APPLICATION

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

3. WIDGETS CAN BE EASILY STARTED, STOPPED OR RESTARTED

Slide 96

Slide 96 text

3. WIDGETS SUBSCRIBE TO NOTIFICATIONS OF INTEREST, RAPIDLY REACT TO CHANGES

Slide 97

Slide 97 text

3. WIDGETS NOTIFY THE APP WHEN SOMETHING INTERESTING HAPPENS (PUBLISH)

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

4. MODULES UNITS OF CODE THAT CAN BE LOADED, UNLOADED OR EASILY RE-USED USING AMD

Slide 101

Slide 101 text

THAT’S IT FOR AURA!

Slide 102

Slide 102 text

REMEMBER, COUPLING IS BAD.

Slide 103

Slide 103 text

Blog Twitter GitHub http://addyosmani.com @addyosmani http://github.com/addyosmani DECOUPLING IS AWESOME.