Slide 1

Slide 1 text

JAVASCRIPT CODE ORGANIZATION, PATTERNS ZACH DENNIS MUTUALLY HUMAN SOFTWARE 1 Monday, March 28, 2011

Slide 2

Slide 2 text

INLINE JAVASCRIPT IS NOT SUSTAINABLE 2 Monday, March 28, 2011

Slide 3

Slide 3 text

POOR MODULARITY / REUSE CODE MAINTENANCE PROBLEMS LACK OF CACHING DIFFICULTY SCALING TO LARGER APPS 3 Monday, March 28, 2011

Slide 4

Slide 4 text

UNOBTRUSIVE JAVASCRIPT PATHWAY TO THE GREAT VALLEY 4 Monday, March 28, 2011

Slide 5

Slide 5 text

2 TECHNIQUES SEPARATE CONTENT FROM BEHAVIOR, REGISTER EVENT HANDLERS PROGRAMMATICALLY 5 Monday, March 28, 2011

Slide 6

Slide 6 text

SEPARATE BEHAVIOR FROM CONTENT $(“.presentation .play”).click(function(){ // ... }); HTML JS 6 Monday, March 28, 2011

Slide 7

Slide 7 text

REGISTER HANDLERS PROGRAMMATICALLY $(“.presentation .play”).click(function(){ // ... }); JQUERY $(“.presentation .play”).addEvent(“click”, function(){ // ... }); MOOTOOLS var el = dojo.query(“.presentation .play”); el.connect(“click”, function(){ // ... }); DOJO 7 Monday, March 28, 2011

Slide 8

Slide 8 text

THE GREAT VALLEY EFFECT 8 Monday, March 28, 2011

Slide 9

Slide 9 text

A BETTER VANTAGE POINT SEE PATTERNS CODE DECOMPOSITION CODE ORGANIZATION APPLY PATTERNS 9 Monday, March 28, 2011

Slide 10

Slide 10 text

DRIVES SEMANTIC SELECTOR DRIVEN CODE 10 Monday, March 28, 2011

Slide 11

Slide 11 text

REINFORCE SEMANTIC MARKUP $(“.presentation .play”).click(function(){ // ... }); JS HTML .presentation .play { background-image: url(...); font-size: 1.em; } CSS 11 Monday, March 28, 2011

Slide 12

Slide 12 text

SELECTOR DRIVEN CODE IT CAN BE SCANNED AND RE-ORGANIZED MORE EFFECTIVELY. IT’S EASIER TO VISUALIZE AND MANIPULATE. 12 Monday, March 28, 2011

Slide 13

Slide 13 text

BUT THEN 13 Monday, March 28, 2011

Slide 14

Slide 14 text

$(".presentation .play").click(function(){ var presentation = $(this).parents('.presentation:first'); presentation.addClass('playing'); selectSlide(presentation.find(".slides:first")); }); $(".presentation .stop").click(function(){ $(this).parents('.deck:first').addClass('stopping'); }); $('.presentation a.destroy').live('ajax:success', function(data){ var deck = $(this).parents('.deck:first'); deck.fadeOut('fast', deck.remove); }); $('#grid .slide a:last').click(function(){ selectSlide($(this).parents(".slide:first")); return false; }); $('img.slide').live("slide:loaded", function(){ resizeSlide($(this)); }); // any time the window resizes, resize the main slide $(window).resize(function(){ resizeSlide($(".slide_viewer img.slide")); }); function resizeSlide(img) { var viewer_width = $('.slide_viewer').width(); var viewer_height = $('.slide_viewer').height(); // Use original width and height since the image may be scaled // down to a smaller size, and we want to use the original size to scale // the image rather than the size it is currently scaled to var slide_width = img.data('original_width'); var slide_height = img.data('original_height'); if(slide_width > viewer_width){ ratio = viewer_width / slide_width; $('.slide_viewer img.slide').css({width: viewer_width, height: slide_height * ratio}); } } page 1 of 22 14 Monday, March 28, 2011

Slide 15

Slide 15 text

MONOLITHIC JAVASCRIPT FORMED OF A SINGLE LARGE FILE. 15 Monday, March 28, 2011

Slide 16

Slide 16 text

CODE MONOLITHS GREAT FOR DEPLOYMENT BAD FOR DEVELOPMENT LOSES CONTEXT, HIERARCHY, SCOPE VISUALLY HARD TO SCAN CODE WITH DIFFERENT BEHAVIORS OR REASONS TO EXIST, CO-EXIST EXCEPT VERY SMALL SITES / APPS 16 Monday, March 28, 2011

Slide 17

Slide 17 text

PATTERNS FOR AVOIDING MONOLITHS TRADITIONAL CLASS-BASED OO FUNCTIONS, CLOSURES EVENT-DRIVEN JAVASCRIPT 17 Monday, March 28, 2011

Slide 18

Slide 18 text

TRADITIONAL CLASS-BASED OO APPLYING TRIED AND TRUE TECHNIQUES WITH JAVASCRIPT 18 Monday, March 28, 2011

Slide 19

Slide 19 text

function Presentation(element) { this._element = element; this.play = element.find(“.play”); this.stop = element.find(“.stop”); this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); }; Presentation.prototype.play = function() { this._element.addClass(“playing”); // ... }; Presentation.prototype.stop = function(hours) { // ... }; JS 19 Monday, March 28, 2011

Slide 20

Slide 20 text

var Presentation = $.Class.create({ initialize: function(element) { this._element = element; this.play = element.find(“.play”); this.stop = element.find(“.stop”); this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); }, play: function(){ this._element.addClass(“playing”); // ... }, stop: function(){ // ... }, }); JQUERY 20 Monday, March 28, 2011

Slide 21

Slide 21 text

var el = $(“.presentation:first”); var prez = new Presentation(prez); prez.play(); prez.stop(); JQUERY USING THE CLASS 21 Monday, March 28, 2011

Slide 22

Slide 22 text

BENEFITS DATA/BEHAVIOR ENCAPSULATION CLEAR BOUNDARIES OF RESPONSIBILITIES API DEFINITION MODULAR / REUSABLE CODE 22 Monday, March 28, 2011

Slide 23

Slide 23 text

ASSIGN PSEUDO-PRIVATE VARIABLE var Presentation = $.Class.create({ initialize: function(element) { this.play = element.find(“.play”); this.stop = element.find(“.stop”); this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); }, play: function(){ // ... }, stop: function(){ // ... }, }); this._element = element; this._element.addClass(“playing”); JQUERY 23 Monday, March 28, 2011

Slide 24

Slide 24 text

var Presentation = $.Class.create({ initialize: function(element) { this._element = element; this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); }, play: function(){ this._element.addClass(“playing”); // ... }, stop: function(){ // ... }, }); this.play = element.find(“.play”); this.stop = element.find(“.stop”); FIND AND ASSIGN ELEMENTS WE NEED ACCESS TO JQUERY 24 Monday, March 28, 2011

Slide 25

Slide 25 text

var Presentation = $.Class.create({ initialize: function(element) { this._element = element; this.play = element.find(“.play”); this.stop = element.find(“.stop”); }, play: function(){ this._element.addClass(“playing”); // ... }, stop: function(){ // ... this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); JQUERY REGISTER EVENT HANDLERS 25 Monday, March 28, 2011

Slide 26

Slide 26 text

var Presentation = $.Class.create({ initialize: function(element) { this._element = element; this.play = element.find(“.play”); this.stop = element.find(“.stop”); }, play: function(){ ._element.addClass(“playing”); // ... }, stop: function(){ // ... this.play.bind(“click”, ); this.stop.bind(“click”, ); JQUERY KEEP REFERENCE TO THIS $.proxy(this.play, this); $.proxy(this.stop, this) this 26 Monday, March 28, 2011

Slide 27

Slide 27 text

FEELS A LITTLE HEAVY FEELS A LITTLE AWKWARD 27 Monday, March 28, 2011

Slide 28

Slide 28 text

SAME EXAMPLE, DIFFERENT PATTERN 28 Monday, March 28, 2011

Slide 29

Slide 29 text

FUNCTIONS, CLOSURES TAKING ADVANTAGE OF JAVASCRIPT 29 Monday, March 28, 2011

Slide 30

Slide 30 text

var Presentation = function(element){ var presentation = element; presentation.delegate(".play", "click", play); presentation.delegate(".stop", "click", stop); function play(){ presentation.addClass(“playing”); // ... } function stop(){ // ... } return { play: play, stop: stop } }; JQUERY FUNCTIONS, SCOPE, CLOSURES 30 Monday, March 28, 2011

Slide 31

Slide 31 text

var el = $(“.presentation:first”); var prez = Presentation(prez); prez.play(); prez.stop(); JQUERY ONLY DIFFERENCE, NO “NEW” 31 Monday, March 28, 2011

Slide 32

Slide 32 text

var Presentation = function(element){ presentation.delegate(".play", "click", play); presentation.delegate(".stop", "click", stop); function play(){ // ... } function stop(){ // ... } return { play: play, stop: stop } }; JQUERY var presentation = element; ACCESSIBLE PRIVATE VARIABLES presentation.addClass(“playing”); 32 Monday, March 28, 2011

Slide 33

Slide 33 text

var Presentation = function(element){ var presentation = element; function play(){ presentation.addClass(“playing”); // ... } function stop(){ // ... } return { play: play, stop: stop } }; JQUERY STRAIGHT FORWARD EVENT DELEGATION presentation.delegate(".play", "click", play); presentation.delegate(".stop", "click", stop); 33 Monday, March 28, 2011

Slide 34

Slide 34 text

var Presentation = function(element){ var presentation = element; presentation.delegate(".play", "click", play); presentation.delegate(".stop", "click", stop); function play(){ presentation.addClass(“playing”); // ... }; function stop(){ // ... }; return { }; }; JQUERY API DEFINITION play: play, stop: stop 34 Monday, March 28, 2011

Slide 35

Slide 35 text

FEELS MORE LIKE HOME 35 Monday, March 28, 2011

Slide 36

Slide 36 text

WHAT IF WE DIDN’T CARE ABOUT A PUBLIC API? 36 Monday, March 28, 2011

Slide 37

Slide 37 text

(function(){ $(".presentation").delegate(".play", "click", play); $(".presentation").delegate(".stop", "click", stop); function play(){ $(this).parents(“.presentation:first”).addClass(“playing”); // ... } function stop(){ // ... } })(); SHORTER. SIMPLER. SWEETER. JQUERY 37 Monday, March 28, 2011

Slide 38

Slide 38 text

CREATED A FUNCTION, EXECUTED IT REMOVE UNNECESSARY VARS RELY ON SELECTOR-DRIVEN EVENT HANDLERS NO NEED TO MANUALLY BIND TO ELEMENTS WHAT JUST HAPPENED? 38 Monday, March 28, 2011

Slide 39

Slide 39 text

var Presentation = (function(element){ var presentation = element; presentation.delegate(".play", "click", play); presentation.delegate(".stop", "click", stop); function play(){ presentation.addClass(“playing”); // ... } function stop(){ // ... } return { play: playPresentation, stop: stopPresentation } }); function(){ $(".presentation").delegate(".play", "click", play); $(".presentation").delegate(".stop", "click", stop); function play(){ $(this).parents(“.presentation:first”).addClass(“playing”); // ... } function stop(){ // ... } }(); var Presentation = $.Class.create({ initialize: function(element) { this._element = element; this.play = element.find(“.play”); this.stop = element.find(“.stop”); this.play.bind(“click”, $.proxy(this.play, this)); this.stop.bind(“click”, $.proxy(this.stop, this)); }, play: function(){ this._element.addClass(“playing”); // ... }, stop: function(){ // ... } }); CLASS-BASED FUNCTION, CLOSURES EVENT-DRIVEN 39 Monday, March 28, 2011

Slide 40

Slide 40 text

FUNCTIONS, CLOSURES RECAP USE FUNCTIONS AND CLOSURES TO CREATE SCOPE PRESERVE PRIVATE METHODS AND PROPERTIES WITH VAR STATEMENTS RETURN PUBLIC METHODS, PROPERTIES (OPTIONAL) AND WE DON’T POLLUTE GLOBAL NAMESPACE 40 Monday, March 28, 2011

Slide 41

Slide 41 text

ONE STEP FURTHER 41 Monday, March 28, 2011

Slide 42

Slide 42 text

EVENT-DRIVEN JAVASCRIPT DECLARATIVELY READABLE SELECTOR DRIVEN CODE 42 Monday, March 28, 2011

Slide 43

Slide 43 text

6 GUIDELINES 43 Monday, March 28, 2011

Slide 44

Slide 44 text

MEANINGFUL FILE NAMES TO ORGANIZE BEHAVIOR PRESENTER.JS VIEWER.JS SLIDES/ PRESENTER/ REMOTE-CONTROLS.JS VIEWER/ RESIZING.JS REMOTE-CONTROLS.JS GRID.JS *USE COMBINATOR, COMPRESSOR, MINIFIER FOR DEPLOYMENT 44 Monday, March 28, 2011

Slide 45

Slide 45 text

STRUCTURE RELIES ON FUNCTION SCOPE (function(){ })(); MODULE $(function(){ }); MODULE JQUERY EXECUTES IMMEDIATELY EXECUTES AFTER DOM READY JS 45 Monday, March 28, 2011

Slide 46

Slide 46 text

DECLARE PAGE CHECKS FIRST $(function(){ }); JQUERY if(!$("html.presenter").length) return; PRESENTER.JS 46 Monday, March 28, 2011

Slide 47

Slide 47 text

DECLARE HANDLERS AND VARS SECOND $(function(){ if(!$("html.presenter").length) return; }); var presentation = $(“.presentation”), attendee_count = 0; presentation.delegate(“.play”, “click”, play); presentation.delegate(“.stop”, “click”, stop); presentation.delegate(“.slide .next”, “click”, nextSlide); presentation.delegate(“.slide .prev”, “click”, prevSlide); JQUERY PRESENTER.JS 47 Monday, March 28, 2011

Slide 48

Slide 48 text

DECLARE FUNCTIONS LAST $(function(){ if(!$("html.presenter").length) return; var presentation = $(“.presentation”), attendee_count = 0; presentation.delegate(“.play”, “click”, play); presentation.delegate(“.stop”, “click”, stop); presentation.delegate(“.slide .next”, “click”, nextSlide); presentation.delegate(“.slide .prev”, “click”, prevSlide); function play(){ // ... }; function stop(){ // ... JQUERY PRESENTER.JS 48 Monday, March 28, 2011

Slide 49

Slide 49 text

QUICKER TO SCAN. KEEPING DECLARATIONS ABOVE FUNCTION DEFINITIONS CREATES MORE READABLE CODE. 49 Monday, March 28, 2011

Slide 50

Slide 50 text

EVENTS DRIVE CROSS-CLOSURE COMMUNICATION function nextSlide(){ var prez = $(this).parents('.presentation:first'); // ... current_slide.removeClass('current'); next_slide.addClass('current'); }; prez.trigger('slide:changed', { slide: next_slide }); $("body").delegate(".presentation", "slide:changed", transitionToSlide); THUMBNAIL-CONTROLS.JS PRESENTER.JS $("body").delegate(".presentation", "slide:changed", changeSlideOnRemoteViewers); REMOTE-VIEWER-CONTROLS.JS _ _ _ 50 Monday, March 28, 2011

Slide 51

Slide 51 text

BENEFITS FUNCTIONS AND CLOSURES ALLOW GROUPING OF COMMON BEHAVIOR AND DATA CUSTOM EVENTS ARE AWESOME NO NEED TO HAVE REFERENCES TO EXTERNAL OBJECTS THROUGHOUT OUR APP LOOSER COUPLING EASIER TO HOOK IN NEW PARTS OF OUR APP WITH MINIMAL IMPACT TO EXISTING CODE 51 Monday, March 28, 2011

Slide 52

Slide 52 text

52 Monday, March 28, 2011

Slide 53

Slide 53 text

EVENT-DRIVEN HOW WE GOT THERE MEANINGFUL DIRECTORY AND FILE NAMES FOLLOW MODULE OR SIMILAR CLOSURE-PATTERN GENERAL GUIDELINES FOR READABILITY: DECLARE PAGE CHECKS FIRST DECLARE HANDLERS AND VARS SECOND DECLARE FUNCTIONS LAST USE EVENTS TO DRIVE CROSS-CLOSURE COMMUNICATION 53 Monday, March 28, 2011

Slide 54

Slide 54 text

54 Monday, March 28, 2011

Slide 55

Slide 55 text

IN SUMMARY INLINE JAVASCRIPT IS NOT A SUSTAINABLE APPROACH. UNOBTRUSIVE JAVASCRIPT IS A PATH TO “THE GREAT VALLEY” MONOLITHIC UJS WORKS FINE FOR SMALL APPS, BUT DOESN’T SCALE WELL. FORTUNATELY SELECTOR-DRIVEN JS IS EASIER TO MANIPULATE AND REORGANIZE. TRADITIONAL CLASS-BASED OO + UJS WORKS WELL, BUT CAN AT TIMES BE A BIT HEAVY FUNCTION/CLOSURES ARE A LIGHTER WEIGHT APPROACH THAN TRADITIONAL OO. FEELS MORE JAVASCRIPTY. EVENT-DRIVEN APPROACH WITH EMPHASIS ON FUNCTION/CLOSURES FOR SCOPE AND DECLARATIVE SELECTOR-DRIVEN CODE IS LEANER, SCALABLE AND PROMOTES LOOSE COOUPLING 55 Monday, March 28, 2011