Pro Yearly is on sale from $80 to $50! »

Zombie Code - Front Trends 2015

Zombie Code - Front Trends 2015

Have you ever had the need to figure out how to survive a Javascript Zombiecodepocalipse? Have you ever dreamt about loads of living legacy code and the urge to run away from it? Hundreds of lines of code tightly coupled and hardly understandable there were trying to catch you?

I’ve been there and I’m a survivor because I learned the art of refactoring.
This talk is about how to deal with features request, deadlines and still increase the maintainability of your code.

3ca63d4e2f2be0ef47b841e63b564d18?s=128

Marco Cedaro

May 07, 2015
Tweet

Transcript

  1. TALK

  2. Zombie Code

  3. Zombie Code how to survive a Javascript Zombiecodeapocalypse

  4. First things first my name is @cedmax

  5. cedmax @ Shazam

  6. cedmax @ Shazam Flav Umar Luca Beer ced

  7. Basically Zombies?

  8. Basically Zombies?

  9. Zombies! “Brains, BRAINS, BRains, brains, BRAINS. BRaiNS, brains, Brains, BRAINS,

    BRains, brains, BRAINS. BRAINS, BRains, brains, BRAINS, brains.” Ryan Mecum
  10. ZOMBIE CODE?

  11. it’s not dead code http://alfasin.com/i-see-dead-code-homage-for-intellij-idea/

  12. It may seems harmless http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/

  13. http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/ but it’s NOT

  14. and it will, eventually http://imgur.com/r/SRDBroke/JimqK CODE

  15. during estimation

  16. during debugging

  17. during development

  18. It is dumb code  that makes you dumb as

    well
  19. Hopefully it’s not too late http://tacticaltshirts.com/shop/shirt-zombies-eat-brains/

  20. How to identify Zombie CODE?

  21. What's that smell? Zombies smell worse than anything you can

    imagine Lilith Saintcrow, Strange Angels
  22. 3 tips

  23. TIp #1 Code should be appealing

  24. 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; }
  25. // 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); }
  26. 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; }
  27. HOW LONG IS THAT?

  28. 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; } });
  29. // 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; }
  30. 14 (FOURTEEN!) ifs

  31. 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; } });
  32. // 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; }
  33. are comments a bad thing?

  34. TIp #2 Code should talk to you

  35. _$ = (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) } } })({})
  36. _$ = (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
  37. _$ = (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); } }; })();
  38. don’t use comments as an excuse to write bad code

  39. //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 }
  40. //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
  41. //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 AUTOMATED DOC GENERATION
  42. //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 AUTOMATED DOC GENERATION TODOs
  43. TIp #3 Code should have 
 personal boundaries

  44. Define 
 boundaries

  45. Single responsibility principle your best tool against Zombie Code

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

  47. No coupling http://leosabanganii.blogspot.co.uk/2012/10/zombie-dressed-activists-protest.html http://ajandcharli.blogspot.co.uk/2011/05/we-dont-do-dead-people.html

  48. code-sense is the key Writing clean code requires the disciplined

    use of a myriad little techniques applied through a painstakingly acquired sense of "cleanliness". Robert C. Martin
  49. worst case smell

  50. worst case smell Long methods

  51. worst case smell Long methods Deep Level of Indentation

  52. worst case smell Long methods Deep Level of Indentation Hard

    to tell what it does
  53. worst case smell Long methods Deep Level of Indentation Hard

    to tell what it does Lack of portability
  54. worst case smell Long methods Deep Level of Indentation Hard

    to tell what it does Lack of portability Hardcoded style/templating
  55. worst case smell Long methods Deep Level of Indentation Hard

    to tell what it does Lack of portability Hardcoded style/templating Logic block duplication
  56. 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
  57. And now what?

  58. Play cool!

  59. Basically Quarantine

  60. Basically Quarantine

  61. 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
  62. The broken window

  63. “Don't leave "broken windows" (bad designs, wrong decisions, or poor

    code) unrepaired. Fix each one as soon as it is discovered.” Jeff Atwood
 http://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html The broken window
  64. “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.” Jeff Atwood
 http://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html The broken window
  65. Maybe we should be sweating the small stuff. Jeff Atwood


    http://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html The broken window
  66. Isolate the Zombies

  67. define style guidelines

  68. function Zombie(personName) { function do_something() { console.log(personName + " just

    ate a brain!"); } return { doSomethingZombiesDo: do_something }; } var adam = new Zombie("Adam"); adam.doSomethingZombiesDo();
  69. function Zombie(personName) { function do_something() { console.log(personName + " just

    ate a brain!"); } return { doSomethingZombiesDo: do_something }; } var adam = new Zombie("Adam"); adam.doSomethingZombiesDo();
  70. function Zombie(personName) { function do_something() { console.log(personName + " just

    ate a brain!"); } return { doSomethingZombiesDo: do_something }; } var adam = new Zombie("Adam"); adam.doSomethingZombiesDo();
  71. function Zombie(personName) { function do_something() { console.log(personName + " just

    ate a brain!"); } return { doSomethingZombiesDo: do_something }; } var adam = new Zombie("Adam"); adam.doSomethingZombiesDo();
  72. start linting your code

  73. Inversion of control freakness AM I A CONTROL FREAK?

  74. start testing your code

  75. Unit or Functional?

  76. Do both

  77. As long as it can be automated share identify build

    make it continuous
  78. Make it part of the process Make it part of

    the process
  79. 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/
  80. 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/
  81. 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/
  82. Fear the living? DON’T

  83. The team

  84. DEVOPS PRODUCT OWNER qa

  85. QA

  86. QA Crucial role in the process

  87. QA Crucial role in the process Quality should be your

    goal too
  88. QA Crucial role in the process Quality should be your

    goal too Get help for functional test coverage not to screw up refactoring
  89. Devops

  90. Devops The tough guy

  91. Devops The tough guy It could be hard to deal

    with
  92. Devops The tough guy It could be hard to deal

    with Get help setting up the automated process
  93. Product owner

  94. Product owner The less interested in code itself

  95. Product owner The less interested in code itself Bring numbers,

    not theories
  96. Product owner The less interested in code itself Bring numbers,

    not theories Get help not wasting time, staying focused on functionalities
  97. Others in the company

  98. juniors external lobbyist

  99. Juniors

  100. Juniors Pair with them, code review their (and your) code

  101. Juniors Pair with them, code review their (and your) code

    Involve them during the whole process definition
  102. Juniors Pair with them, code review their (and your) code

    Involve them during the whole process definition Get help keeping things easy and accessible
  103. Learn to say NO!

  104. Learn to say NO! Lobbyists will slow you down, your

    brain will be more prone to be eaten
  105. Learn to say NO! Lobbyists will slow you down, your

    brain will be more prone to be eaten Redirect them to the product owner
  106. Basically KILL ‘EM ALL (AGAIN?)

  107. Basically KILL ‘EM ALL (AGAIN?)

  108. KILL ‘EM ALL (AGAIN?) “Nothing is impossible to kill.” Mira

    Grant, Feed
  109. but

  110. “Without requirements or design, programming is the art of adding

    bugs to an empty text file” Louis Srygley Design for your goal
  111. Design for your goal

  112. ākāśe  sanskrit for "in the sky"/"to the sky" https://github.com/cedmax/akase

  113. Modular Architecture

  114. None
  115. Scalable JavaScript Application Architecture by Nicholas Zakas

  116. None
  117. None
  118. core.register("module-name", function(sandbox){ return { init:function(){ }, destroy:function(){ } }; });

  119. core.register("module-name", function(sandbox){ return { init:function(){ }, destroy:function(){ } }; });

  120. core.register("module-name", function(sandbox){ return { init:function(){ }, destroy:function(){ } }; });

  121. None
  122. None
  123. core.register("module-name", function(sandbox){ return { init:function(){ var user = sandbox.getUser(); },

    destroy:function(){ } }; });
  124. core.register("module-name", function(sandbox){ return { init:function(){ var user = sandbox.getUser(); },

    destroy:function(){ } }; });
  125. None
  126. 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');
  127. 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');
  128. 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');
  129. 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');
  130. 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');
  131. 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');
  132. None
  133. None
  134. Event Driven Pattern

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

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

    }; });
  137. sandbox.layer("an error occured");

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

  139. sandbox.publish("error", { msg: "an error occured" }); core.register("errManager", function(sandbox){ return

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

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

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

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

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

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

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

    { init: function(){ sandbox.subscribe("error", function(err) { console.log(err.msg) }); } }; });
  147. sandbox.subscribe("error", function(payload){ console.log(payload.msg); }); Advantages

  148. sandbox.subscribe("error", function(payload){ console.log(payload.msg); }); Advantages SEMANTIC

  149. sandbox.subscribe("error", function(payload){ console.log(payload.msg); }); Advantages SEMANTIC flexibility

  150. Advantages DECOUPLING

  151. “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?
  152. AMD

  153. //API: define(id?, dependencies?, factory); define("My-Module", ["Another-Module"], function(AnotherModule){ // Do Something

    }); one define to rule them all
  154. //API: define(id?, dependencies?, factory); define("My-Module", ["Another-Module"], function(AnotherModule){ // Do Something

    }); one define to rule them all
  155. //app/config.js define([], function() { return { url: "http://whatever.it/is/", debug: true

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

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

    }; });
  158. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  159. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  160. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  161. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  162. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  163. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  164. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  165. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  166. //app/myProduct.js define(["app/config"], function(config) { return function(id){ return { getProductUrl: function(){

    var prodPath = config.url + "product/" + id; if (config.debug){ console.log(prodPath) } return prodPath; } }; }; });
  167. <script data-main="app/main" src="require.js"></script>

  168. <script data-main="app/main" src="require.js"></script> //app/main.js require(["jQuery", "app/myProduct"], function($, Product) { $(".product").on("click",

    function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); }) });
  169. <script data-main="app/main" src="require.js"></script> //app/main.js require(["jQuery", "app/myProduct"], function($, Product) { $(".product").on("click",

    function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); }) });
  170. <script data-main="app/main" src="require.js"></script> //app/main.js require(["jQuery", "app/myProduct"], function($, Product) { $(".product").on("click",

    function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); }) });
  171. <script data-main="app/main" src="require.js"></script> //app/main.js require(["jQuery", "app/myProduct"], function($, Product) { $(".product").on("click",

    function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); }) });
  172. <script data-main="app/main" src="require.js"></script> //app/main.js require(["jQuery", "app/myProduct"], function($, Product) { $(".product").on("click",

    function(){ var prodID = $(this).data("id"); var prod = new Product(prodID); document.location.href = prod.getProductUrl(); }) });
  173. Pulling all together

  174. 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 } }; }; });
  175. 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 } }; }; });
  176. 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 } }; }; });
  177. 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 } }; }; });
  178. 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 } }; }; });
  179. require(["akase"], function(core) { core.start("module1"); core.start("module2", { config: { debug: true

    } }); core.start("module3", { event: "audio:stop" }); });
  180. require(["akase"], function(core) { core.start("module1"); core.start("module2", { config: { debug: true

    } }); core.start("module3", { event: "audio:stop" }); });
  181. require(["akase"], function(core) { core.start("module1"); core.start("module2", { config: { debug: true

    } }); core.start("module3", { event: "audio:stop" }); });
  182. require(["akase"], function(core) { core.start("module1"); core.start("module2", { config: { debug: true

    } }); core.start("module3", { event: "audio:stop" }); });
  183. require(["akase"], function(core) { core.start("module1"); core.start("module2", { config: { debug: true

    } }); core.start("module3", { event: "audio:stop" }); });
  184. ākāśe  sanskrit for "in the sky"/"to the sky" https://github.com/cedmax/akase

  185. 2 years later…

  186. require = { baseUrl: '/assets/js/module', shim: { 'magnificpopup': { deps:

    ['jquery'] }, 'timezone': { exports: 'jstz'}, 'facebook': { exports: 'FB' } }, paths: { 'templates': '../../templates', 'widget': '../widget', 'core': '../core', 'packages': '../packages', 'jquery': 'js/vendor/jquery-2.0.0.min.js', 'magnificpopup': 'js/vendor/mpopup-0.9.2.min.js', 'modernizr': 'js/vendor/modernizr.min.js', 'fastclick': 'js/vendor/fastclick-1.0.2.min.js', 'timezone': 'js/vendor/timezone-1.0.4.min.js', 'typeahead': 'js/vendor/typeahead-0.9.3.min.js' }, waitSeconds:30 };
  187. var $ = require("jquery"); // Do Something var myscript =

    require("myscript"); var anotherDep = require("anotherDep"); // Do Something else COMMON JS require([ "jquery", "myscript", "anotherDep", ], function($, myscript, anotherDep){ // Do Something }); REQUIRE JS
  188. import $ from 'jquery'; import myscript from 'myscript'; import anotherDep

    from 'anotherDep'; // Do Something ES6
  189. No such thing!

  190. Basically Happy Endings?

  191. Basically Happy Endings?

  192. “If you want a happy ending, that depends, of course,

    on where you stop your story.” Orson Wells Happy ending
  193. You can run, you can hide

  194. You are going to SHITTY code anyway write

  195. You are going to write Zombie code anyway

  196. Embrace it! http://drezner.foreignpolicy.com/posts/2009/08/18/theory_of_international_politics_and_zombies

  197. Don’t improvise

  198. Learn how to deal with it

  199. Until you master it

  200. in any case just  remember to

  201. Aim for the head http://halloween.squidoo.com/get-spooked/aim-for-the-head

  202. None
  203. marco@fromthefront.it http://cedmax.com @cedmax any question?