Top Banner
TALK
196

ZombieCode

Nov 14, 2014

Download

Technology

FDConf

by Marco Cedaro on Frontend DEV Conf'13
http://bit.ly/Marco_Cedaro
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: ZombieCode

TALK

Page 2: ZombieCode

Zombie Code

Page 3: ZombieCode

Zombie Codehow to survive a Javascript

Zombiecodeapocalypse

Page 4: ZombieCode

First things first

my name is @cedmax

I work for Shazam

I organize conferences with From The Front

Page 5: ZombieCode

DISCLAIMER

Page 6: ZombieCode

DISCLAIMER

I’m strongly opinionated

Page 7: ZombieCode

DISCLAIMER

I’m strongly opinionated

it’s a gift and a curse

Page 8: ZombieCode

BasicallyZombies?

Page 9: ZombieCode

BasicallyZombies?

Page 10: ZombieCode

Zombies!

“Brains, BRAINS, BRains, brains, BRAINS.BRaiNS, brains, Brains, BRAINS, BRains,

brains, BRAINS.BRAINS, BRains, brains, BRAINS, brains.”

Ryan Mecum

Page 11: ZombieCode

ZOMBIE CODE?

Page 12: ZombieCode

it’s not dead code

http://alfasin.com/i-see-dead-code-homage-for-intellij-idea/

Page 13: ZombieCode

How to identifyZombie CODE?

Page 14: ZombieCode

What I can tell is..

Page 15: ZombieCode

It may seems harmless

http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/

Page 16: ZombieCode

http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/

but it’s NOT

Page 18: ZombieCode

during estimation

Page 19: ZombieCode

during debugging

Page 20: ZombieCode

during development

Page 21: ZombieCode

It is dumb code that makes you dumb as well

Page 22: ZombieCode

Hopefully it’s not too late

http://tacticaltshirts.com/shop/shirt-zombies-eat-brains/

Page 23: ZombieCode

What's that smell?

Zombies smell worse than anything you can imagine

Lilith Saintcrow, Strange Angels

Page 24: ZombieCode

TIp #1

Code should be appealing

Page 25: ZombieCode

function validate( options ) {

// if nothing is selected, return nothing; can't chain anyway if ( !this.length ) { if ( options && options.debug && window.console ) { console.warn( "Nothing selected, can't validate, returning nothing." ); } return; }

// check if a validator for this form was already created var validator = $.data( this[0], "validator" ); if ( validator ) { return validator; }

// Add novalidate tag if HTML5. this.attr( "novalidate", "novalidate" );

validator = new $.validator( options, this[0] ); $.data( this[0], "validator", validator );

if ( validator.settings.onsubmit ) {

this.validateDelegate( ":submit", "click", function( event ) { if ( validator.settings.submitHandler ) {

validator.submitButton = event.target; }

Page 26: ZombieCode

// allow suppressing validation by adding a cancel class to the submit button

if ( $(event.target).hasClass("cancel") ) { validator.cancelSubmit = true; }

// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button if ( $(event.target).attr("formnovalidate") !== undefined ) { validator.cancelSubmit = true; } });

// validate the form on submit this.submit( function( event ) { if ( validator.settings.debug ) { // prevent form submit to be able to see console output event.preventDefault(); } function handle() { var hidden; if ( validator.settings.submitHandler ) { if ( validator.submitButton ) { // insert a hidden input as a replacement for the missing submit button hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm); }

Page 27: ZombieCode

validator.settings.submitHandler.call( validator, validator.currentForm, event );

if ( validator.submitButton ) { // and clean up afterwards; thanks to no-block-scope, hidden can be referenced hidden.remove(); } return false; } return true; }

// prevent submit for invalid forms or custom submit handlers if ( validator.cancelSubmit ) { validator.cancelSubmit = false; return handle(); } if ( validator.form() ) { if ( validator.pendingRequest ) { validator.formSubmitted = true; return false; } return handle(); } else { validator.focusInvalid(); return false; } }); }

return validator;}

Page 28: ZombieCode

HOW LONG IS THAT?

Page 29: ZombieCode

function validate( options ) {

// if nothing is selected, return nothing; can't chain anyway if ( !this.length ) { if ( options && options.debug && window.console ) { console.warn( "Nothing selected, can't validate, returning nothing." ); } return; }

// check if a validator for this form was already created var validator = $.data( this[0], "validator" ); if ( validator ) { return validator; }

// Add novalidate tag if HTML5. this.attr( "novalidate", "novalidate" );

validator = new $.validator( options, this[0] ); $.data( this[0], "validator", validator );

if ( validator.settings.onsubmit ) {

this.validateDelegate( ":submit", "click", function( event ) { if ( validator.settings.submitHandler ) { validator.submitButton = event.target; } // allow suppressing validation by adding a cancel class to the submit button if ( $(event.target).hasClass("cancel") ) { validator.cancelSubmit = true; }

// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button if ( $(event.target).attr("formnovalidate") !== undefined ) { validator.cancelSubmit = true; } });

Page 30: ZombieCode

// validate the form on submit this.submit( function( event ) { if ( validator.settings.debug ) { // prevent form submit to be able to see console output event.preventDefault(); } function handle() { var hidden; if ( validator.settings.submitHandler ) { if ( validator.submitButton ) { // insert a hidden input as a replacement for the missing submit button hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm); } validator.settings.submitHandler.call( validator, validator.currentForm, event ); if ( validator.submitButton ) { // and clean up afterwards; thanks to no-block-scope, hidden can be referenced hidden.remove(); } return false; } return true; }

// prevent submit for invalid forms or custom submit handlers if ( validator.cancelSubmit ) { validator.cancelSubmit = false; return handle(); } if ( validator.form() ) { if ( validator.pendingRequest ) { validator.formSubmitted = true; return false; } return handle(); } else { validator.focusInvalid(); return false; } }); }

return validator;}

Page 31: ZombieCode

14 (FOURTEEN!) ifs

Page 32: ZombieCode

function validate( options ) {

// if nothing is selected, return nothing; can't chain anyway if ( !this.length ) { if ( options && options.debug && window.console ) { console.warn( "Nothing selected, can't validate, returning nothing." ); } return; }

// check if a validator for this form was already created var validator = $.data( this[0], "validator" ); if ( validator ) { return validator; }

// Add novalidate tag if HTML5. this.attr( "novalidate", "novalidate" );

validator = new $.validator( options, this[0] ); $.data( this[0], "validator", validator );

if ( validator.settings.onsubmit ) {

this.validateDelegate( ":submit", "click", function( event ) { if ( validator.settings.submitHandler ) { validator.submitButton = event.target; } // allow suppressing validation by adding a cancel class to the submit button if ( $(event.target).hasClass("cancel") ) { validator.cancelSubmit = true; }

// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button if ( $(event.target).attr("formnovalidate") !== undefined ) { validator.cancelSubmit = true; } });

Page 33: ZombieCode

// validate the form on submit this.submit( function( event ) { if ( validator.settings.debug ) { // prevent form submit to be able to see console output event.preventDefault(); } function handle() { var hidden; if ( validator.settings.submitHandler ) { if ( validator.submitButton ) { // insert a hidden input as a replacement for the missing submit button hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm); } validator.settings.submitHandler.call( validator, validator.currentForm, event ); if ( validator.submitButton ) { // and clean up afterwards; thanks to no-block-scope, hidden can be referenced hidden.remove(); } return false; } return true; }

// prevent submit for invalid forms or custom submit handlers if ( validator.cancelSubmit ) { validator.cancelSubmit = false; return handle(); } if ( validator.form() ) { if ( validator.pendingRequest ) { validator.formSubmitted = true; return false; } return handle(); } else { validator.focusInvalid(); return false; } }); }

return validator;}

Page 34: ZombieCode

are comments a bad thing?

Page 35: ZombieCode

TIp #2

Code should talk to you

Page 36: ZombieCode

_$ = (function(_) { return { pub: function(a, b, c, d) { for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b) }, sub: function(a, b) { (_[a] || (_[a] = [])).push(b) } }})({})

Page 37: ZombieCode

_$ = (function(_) { return { pub: function(a, b, c, d) { for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b) }, sub: function(a, b) { (_[a] || (_[a] = [])).push(b) } }})({})

#140bytes

Page 38: ZombieCode

_$ = (function() { var registered = {};

return {

pub: function(event, memo) { if (registered[event] instanceof Array){ var handlers = [].concat(registered[event]);

for (var i=0, handler; (handler = handlers[i]); i++){ handler.call(this, memo); } } }, sub: function(event, handler) { if (typeof registered[event] === "undefined"){ registered[event] = []; } registered[event].push(handler); }

};})();

Page 39: ZombieCode

don’t use comments as an excuse to write bad code

Page 40: ZombieCode

//used translate3d to trigger hardware acceleration in webViews//http://www.youtube.com/watch?v=IKl78ZgJzm4.animated { translate: translate3d(0,0,0)}

/** * Returns a unique ID for use in HTML id attribute. * @param {String/Number} nr A name or number of the ID. * @param {String} [prefix="id-"] The prefix for the ID. * @return {String} the new ID */function createId(nr, prefix){ //TODO implementation}

Page 41: ZombieCode

//used translate3d to trigger hardware acceleration in webViews//http://www.youtube.com/watch?v=IKl78ZgJzm4.animated { translate: translate3d(0,0,0)}

/** * Returns a unique ID for use in HTML id attribute. * @param {String/Number} nr A name or number of the ID. * @param {String} [prefix="id-"] The prefix for the ID. * @return {String} the new ID */function createId(nr, prefix){ //TODO implementation}

un-avoidable

hacks explanation

Page 42: ZombieCode

//used translate3d to trigger hardware acceleration in webViews//http://www.youtube.com/watch?v=IKl78ZgJzm4.animated { translate: translate3d(0,0,0)}

/** * Returns a unique ID for use in HTML id attribute. * @param {String/Number} nr A name or number of the ID. * @param {String} [prefix="id-"] The prefix for the ID. * @return {String} the new ID */function createId(nr, prefix){ //TODO implementation}

un-avoidable

hacks explanationAUTOMATED DOC

GENERATION

Page 43: ZombieCode

//used translate3d to trigger hardware acceleration in webViews//http://www.youtube.com/watch?v=IKl78ZgJzm4.animated { translate: translate3d(0,0,0)}

/** * Returns a unique ID for use in HTML id attribute. * @param {String/Number} nr A name or number of the ID. * @param {String} [prefix="id-"] The prefix for the ID. * @return {String} the new ID */function createId(nr, prefix){ //TODO implementation}

un-avoidable

hacks explanationAUTOMATED DOC

GENERATION

TODOs

Page 44: ZombieCode

TIp #3

Code should have boundaries

Page 45: ZombieCode

Single responsibility

principle

your best tool against Zombie Code

since1902(guaranteed 20 years)

Page 46: ZombieCode

No global pollution

http://leosabanganii.blogspot.co.uk/2012/10/zombie-dressed-activists-protest.html

Page 47: ZombieCode

No coupling

http://leosabanganii.blogspot.co.uk/2012/10/zombie-dressed-activists-protest.htmlhttp

://aj

andc

harl

i.blo

gspo

t.co.

uk/2

011/

05/w

e-do

nt-d

o-de

ad-p

eopl

e.ht

ml

Page 48: ZombieCode

worst case smell

Page 49: ZombieCode

worst case smell

Long methods

Page 50: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Page 51: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Hard to tell what it does

Page 52: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Hard to tell what it does

Lack of portability

Page 53: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Hard to tell what it does

Lack of portability

Hardcoded style/templating

Page 54: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Hard to tell what it does

Lack of portability

Hardcoded style/templating

Logic block duplication

Page 55: ZombieCode

worst case smell

Long methods

Deep Level of Indentation

Hard to tell what it does

Lack of portability

Hardcoded style/templating

Logic block duplication

Callback hell

Page 56: ZombieCode

And now what?

Page 57: ZombieCode

Play cool!

Page 58: ZombieCode

BasicallyQuarantine

Page 59: ZombieCode

BasicallyQuarantine

Page 60: ZombieCode

QUARANTINE

Most teams are trying to stop further spread only through quarantines. It's a good

short-term solution, but it won't prevent long-term population loss.

http://cdmx.it/quarantinequote

Page 61: ZombieCode

The broken window

Page 62: ZombieCode

“Don't leave "broken windows" (bad designs, wrong decisions, or poor code) unrepaired. Fix each one as soon as it is discovered.”Programming is insanely detail oriented, and perhaps this is why: if you're not on top of the details, the perception is that things are out of control, and it's only a matter of time before your project spins out of control. Maybe we should be sweating the small stuff.

Jeff Atwoodhttp://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html

The broken window

Page 63: ZombieCode

Maybe we should be sweating the small stuff.

Jeff Atwoodhttp://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html

The broken window

Page 64: ZombieCode

Isolate the Zombies

Page 65: ZombieCode

define style guidelines

Page 66: ZombieCode

function Zombie(personName) { function do_something() { console.log(personName + " just ate a brain!"); }

return { doSomethingZombiesDo: do_something };

}

var adam = new Zombie("Adam");adam.doSomethingZombiesDo();

Page 67: ZombieCode

function Zombie(personName) { function do_something() { console.log(personName + " just ate a brain!"); }

return { doSomethingZombiesDo: do_something };

}

var adam = new Zombie("Adam");adam.doSomethingZombiesDo();

Page 68: ZombieCode

function Zombie(personName) { function do_something() { console.log(personName + " just ate a brain!"); }

return { doSomethingZombiesDo: do_something };

}

var adam = new Zombie("Adam");adam.doSomethingZombiesDo();

Page 69: ZombieCode

function Zombie(personName) { function do_something() { console.log(personName + " just ate a brain!"); }

return { doSomethingZombiesDo: do_something };

}

var adam = new Zombie("Adam");adam.doSomethingZombiesDo();

Page 70: ZombieCode

define style guidelines

Page 71: ZombieCode

start linting your code

Page 72: ZombieCode

Inversion of control freakness

AM I A CONTROL FREAK?

Page 73: ZombieCode

start testing your code

Page 74: ZombieCode

Unit or Functional?

Page 75: ZombieCode

Do both

Page 76: ZombieCode

What to test

Unit testing is supposed to test a

single atomic “unit” of functionality without

dependencies on anything else

Page 77: ZombieCode

What to test

Unit testing is supposed to test a

single atomic “unit” of functionality without

dependencies on anything else

This is where you start to run into serious

dependency problems due to the interrelation

HTML and CSS

Page 78: ZombieCode

What to test

Unit testing is supposed to test a

single atomic “unit” of functionality without

dependencies on anything else

This is where you start to run into serious

dependency problems due to the interrelation

HTML and CSS

What do you test? Usually how the user interface responds to

user input. Actually, the realm of

functional testing

Page 79: ZombieCode

No matter which toolset

Grunt

PhantomJS

JsTestDriver

Buster.js

Karma

Chutzpah

Testem

Qunit

Mocha

Jasmine

Page 80: ZombieCode

No matter which toolset

Grunt

PhantomJS

JsTestDriver

Buster.js

Karma

Chutzpah

Testem

Qunit

Mocha

Jasmine

Page 81: ZombieCode

As long as it can be automated

share

identify

build

make it continuous

Page 82: ZombieCode

Make it part of the process

Page 83: ZombieCode

Make it part of the process

http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/

Estimate testing

http://malyn.edublogs.org/2011/10/16/process-tools-people/

Page 84: ZombieCode

Make it part of the process

Do code review

http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/

http://malyn.edublogs.org/2011/10/16/process-tools-people/

Page 85: ZombieCode

Make it part of the process

http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/

Involve people

http://malyn.edublogs.org/2011/10/16/process-tools-people/

Page 86: ZombieCode

Fear the living? DON’T

Page 87: ZombieCode

The team

Page 88: ZombieCode

DEVOPS PRODUCT OWNER

qa

Page 89: ZombieCode

QA

Page 90: ZombieCode

QA

Crucial role in the process

Page 91: ZombieCode

QA

Crucial role in the process

Quality should be your goal too

Page 92: ZombieCode

QA

Crucial role in the process

Quality should be your goal too

Get help for functional test coverage not to screw up refactoring

Page 93: ZombieCode

Devops

Page 94: ZombieCode

Devops

The tough guy

Page 95: ZombieCode

Devops

The tough guy

It could be hard to deal with

Page 96: ZombieCode

Devops

The tough guy

It could be hard to deal with

Get help setting up the automated process

Page 97: ZombieCode

Product owner

Page 98: ZombieCode

Product owner

The less interested in code itself

Page 99: ZombieCode

Product owner

The less interested in code itself

Bring numbers, not theories

Page 100: ZombieCode

Product owner

The less interested in code itself

Bring numbers, not theories

Get help not wasting time, staying focused on functionalities

Page 101: ZombieCode

Others in the team

Page 102: ZombieCode

juniorsexternal lobbyist

Page 103: ZombieCode

Juniors

Page 104: ZombieCode

Juniors

Pair with them, code review their (and your) code

Page 105: ZombieCode

Juniors

Pair with them, code review their (and your) code

Involve them during the whole process definition

Page 106: ZombieCode

Juniors

Pair with them, code review their (and your) code

Involve them during the whole process definition

Get help keeping things easy and accessible

Page 107: ZombieCode

Lobbyists

Page 108: ZombieCode

Lobbyists

They will slow you down, your brain will be more prone to be eaten

Page 109: ZombieCode

Lobbyists

They will slow you down, your brain will be more prone to be eaten

Redirect them to the product owner

Page 110: ZombieCode

BasicallyKILL ‘EM ALL (AGAIN?)

Page 111: ZombieCode

BasicallyKILL ‘EM ALL (AGAIN?)

Page 112: ZombieCode

KILL ‘EM ALL (AGAIN?)

“Nothing is impossible to kill.”Mira Grant, Feed

Page 113: ZombieCode

but

Page 114: ZombieCode

“Without requirements or design, programming is the art of adding bugs to an empty text file”

Louis Srygley

Design for your goal

Page 115: ZombieCode

Design for your goal

Page 116: ZombieCode

Modular Architecture

Page 117: ZombieCode
Page 118: ZombieCode

Scalable JavaScript Application

Architecture

by Nicholas Zakas

Page 119: ZombieCode
Page 120: ZombieCode
Page 121: ZombieCode

core.register("module-name", function(sandbox){

return { init:function(){ }, destroy:function(){ } };

});

Page 122: ZombieCode

core.register("module-name", function(sandbox){

return { init:function(){ }, destroy:function(){ } };

});

Page 123: ZombieCode

core.register("module-name", function(sandbox){

return { init:function(){ }, destroy:function(){ } };

});

Page 124: ZombieCode
Page 125: ZombieCode
Page 126: ZombieCode

core.register("module-name", function(sandbox){

return { init:function(){ var user = sandbox.getUser(); }, destroy:function(){ } };

});

Page 127: ZombieCode

core.register("module-name", function(sandbox){

return { init:function(){ var user = sandbox.getUser(); }, destroy:function(){ } };

});

Page 128: ZombieCode
Page 129: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 130: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 131: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 132: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 133: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 134: ZombieCode

core.register('module-name', function(sandbox){

return { init:function(config){ console.log(config.id); } };

});

core.configure('module-name', { id: 'container',});

core.start('module-name');

core.stop('module-name');

Page 135: ZombieCode
Page 136: ZombieCode
Page 137: ZombieCode

Event Driven Pattern

Page 138: ZombieCode

core.register("module-name", function(sandbox){ return { init:function(){ sandbox.layer("an error occured"); } };});

Page 139: ZombieCode

core.register("module-name", function(sandbox){ return { init:function(){ sandbox.layer("an error occured"); } };});

Page 140: ZombieCode

sandbox.layer("an error occured");

Page 141: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

Page 142: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 143: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 144: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 145: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 146: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 147: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 148: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 149: ZombieCode

sandbox.publish("error", { msg: "an error occured"});

core.register("errManager", function(sandbox){ return { init:function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } };});

Page 150: ZombieCode

sandbox.subscribe("error", function(payload){

console.log(payload.msg);

});

Advantages

Page 151: ZombieCode

sandbox.subscribe("error", function(payload){

console.log(payload.msg);

});

Advantages

SEMANTIC

Page 152: ZombieCode

sandbox.subscribe("error", function(payload){

console.log(payload.msg);

});

Advantages

SEMANTIC

flexibility

Page 153: ZombieCode

Advantages

DECOUPLING

Page 154: ZombieCode

“The key is to acknowledge from the start that you have no idea how this will grow. When you accept that you don’t know everything, you begin to design the system defensively.”

Nicholas Zakas

Overengineering?

Page 155: ZombieCode

AMD

Page 156: ZombieCode

icon by http://www.deleket.com/

jQuery

Mustache

Libraries Plugins Your scripts

Page 157: ZombieCode

icon by http://www.deleket.com/

jQuery

Mustache

Libraries Plugins Your scripts

Page 158: ZombieCode

<script src="jquery.min.js"></script><script src="mustache.js"></script>

<?php if ($env == "prod") : ?> <script src="my-code-bundle.js"></script><?php else: ?> <script src="jquery.plugin_1.js"></script> <script src="jquery.plugin_2.js"></script> <script src="my-code_1.js"></script> <script src="my-code_2.js"></script> <script src="my-code_3.js"></script> <script src="my-code_4.js"></script> <script src="my-code_5.js"></script><?php endif; ?>

Page 159: ZombieCode

var MyNamespace = {};

MyNamespace.MyAwesomeLibrary = function() { //implementation};MyNamespace.AnotherCoolOne = function() { //implementation};MyNamespace.SlightlyCrappyLibrary = function() { //implementation};MyNamespace.BestLibEver = function() { //implementation};

Page 160: ZombieCode

//API: define(id?, dependencies?, factory);

define("My-Module", ["Another-Module"], function(AnotherModule){ // Do Something });

one define to rule them all

Page 161: ZombieCode

//API: define(id?, dependencies?, factory);

define("My-Module", ["Another-Module"], function(AnotherModule){ // Do Something });

one define to rule them all

Page 162: ZombieCode

//app/config.jsdefine([], function() { return { url: "http://whatever.it/is/", debug: true };});

Page 163: ZombieCode

//app/config.jsdefine([], function() { return { url: "http://whatever.it/is/", debug: true };});

//app/config.jsdefine({ url: "http://whatever.it/is/", debug: true});

Page 164: ZombieCode

//app/config.jsdefine([], function() { return { url: "http://whatever.it/is/", debug: true };});

//app/config.jsdefine({ url: "http://whatever.it/is/", debug: true});

Page 165: ZombieCode

//app/config.jsdefine([], function() { return { url: "http://whatever.it/is/", debug: true };});

//app/config.jsdefine({ url: "http://whatever.it/is/", debug: true});

Page 166: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 167: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 168: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 169: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 170: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 171: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 172: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 173: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 174: ZombieCode

//app/myProduct.jsdefine(["app/config"], function(config) {

return function(id){ return { getProductUrl: function(){ var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; };});

Page 175: ZombieCode

<script data-main="app/main" src="require.js"></script>

Page 176: ZombieCode

<script data-main="app/main" src="require.js"></script>

//app/main.jsrequire(["jQuery", "app/myProduct"], function($, Product) {

$(".product").on("click", function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); })

});

Page 177: ZombieCode

<script data-main="app/main" src="require.js"></script>

//app/main.jsrequire(["jQuery", "app/myProduct"], function($, Product) {

$(".product").on("click", function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); })

});

Page 178: ZombieCode

<script data-main="app/main" src="require.js"></script>

//app/main.jsrequire(["jQuery", "app/myProduct"], function($, Product) {

$(".product").on("click", function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); })

});

Page 179: ZombieCode

<script data-main="app/main" src="require.js"></script>

//app/main.jsrequire(["jQuery", "app/myProduct"], function($, Product) {

$(".product").on("click", function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); })

});

Page 180: ZombieCode

<script data-main="app/main" src="require.js"></script>

//app/main.jsrequire(["jQuery", "app/myProduct"], function($, Product) {

$(".product").on("click", function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); })

});

Page 181: ZombieCode

Pulling all together

Page 182: ZombieCode

define(function(){ 'use strict';

return function(sandbox){

//the logic of the module function doSomething(){ //do something }

return { init:function(config){ //the initialization code sandbox.subscribe('myEventName', doSomething) }, destroy: function(){ //optional destroy method } }; };});

Page 183: ZombieCode

define(function(){ 'use strict';

return function(sandbox){

//the logic of the module function doSomething(){ //do something }

return { init:function(config){ //the initialization code sandbox.subscribe('myEventName', doSomething) }, destroy: function(){ //optional destroy method } }; };});

Page 184: ZombieCode

define(function(){ 'use strict';

return function(sandbox){

//the logic of the module function doSomething(){ //do something }

return { init:function(config){ //the initialization code sandbox.subscribe('myEventName', doSomething) }, destroy: function(){ //optional destroy method } }; };});

Page 185: ZombieCode

define(function(){ 'use strict';

return function(sandbox){

//the logic of the module function doSomething(){ //do something }

return { init:function(config){ //the initialization code sandbox.subscribe('myEventName', doSomething) }, destroy: function(){ //optional destroy method } }; };});

Page 186: ZombieCode

define(function(){ 'use strict';

return function(sandbox){

//the logic of the module function doSomething(){ //do something }

return { init:function(config){ //the initialization code sandbox.subscribe('myEventName', doSomething) }, destroy: function(){ //optional destroy method } }; };});

Page 187: ZombieCode

require(["akase"], function(core) {

core.start("module1"); core.start("module2", { config: { debug: true } });

core.start("module3", { event: "audio:stop" });

});

Page 188: ZombieCode

require(["akase"], function(core) {

core.start("module1"); core.start("module2", { config: { debug: true } });

core.start("module3", { event: "audio:stop" });

});

Page 189: ZombieCode

require(["akase"], function(core) {

core.start("module1"); core.start("module2", { config: { debug: true } });

core.start("module3", { event: "audio:stop" });

});

Page 190: ZombieCode

require(["akase"], function(core) {

core.start("module1"); core.start("module2", { config: { debug: true } });

core.start("module3", { event: "audio:stop" });

});

Page 191: ZombieCode

require(["akase"], function(core) {

core.start("module1"); core.start("module2", { config: { debug: true } });

core.start("module3", { event: "audio:stop" });

});

Page 192: ZombieCode

ākāśe sanskrit for "in the sky"/"to the sky"

https://github.com/cedmax/akase

Page 193: ZombieCode

No such this thing!

Page 194: ZombieCode

BasicallyHappy Endings?

Page 195: ZombieCode

BasicallyHappy Endings?

Page 196: ZombieCode

you are going to write zombie code

zombie code will always be out there

live with it, embrace it, have a strategy to deal with it