Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Marco Cedaro

May 07, 2015
Tweet

More Decks by Marco Cedaro

Other Decks in Technology

Transcript

  1. Zombie Code
    how to survive a Javascript
    Zombiecodeapocalypse

    View full-size slide

  2. First things first
    my name is
    @cedmax

    View full-size slide

  3. cedmax @ Shazam

    View full-size slide

  4. cedmax @ Shazam
    Flav
    Umar
    Luca
    Beer
    ced

    View full-size slide

  5. Basically
    Zombies?

    View full-size slide

  6. Basically
    Zombies?

    View full-size slide

  7. Zombies!
    “Brains, BRAINS, BRains, brains, BRAINS.
    BRaiNS, brains, Brains, BRAINS, BRains,
    brains, BRAINS.
    BRAINS, BRains, brains, BRAINS, brains.”
    Ryan Mecum

    View full-size slide

  8. ZOMBIE CODE?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  13. during estimation

    View full-size slide

  14. during debugging

    View full-size slide

  15. during development

    View full-size slide

  16. It is dumb code
    that makes you dumb as well

    View full-size slide

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

    View full-size slide

  18. How to identify
    Zombie CODE?

    View full-size slide

  19. What's that smell?
    Zombies smell worse than
    anything you can imagine
    Lilith Saintcrow, Strange Angels

    View full-size slide

  20. TIp #1
    Code should be appealing

    View full-size slide

  21. 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;
    }

    View full-size slide

  22. // 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 = $("").attr("name",
    validator.submitButton.name).val( $
    (validator.submitButton).val() ).appendTo(validator.currentForm);
    }

    View full-size slide

  23. 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;
    }

    View full-size slide

  24. HOW LONG IS THAT?

    View full-size slide

  25. 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;
    }
    });

    View full-size slide

  26. // 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 = $("").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;
    }

    View full-size slide

  27. 14 (FOURTEEN!) ifs

    View full-size slide

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

    View full-size slide

  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 = $("").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;
    }

    View full-size slide

  30. are comments a bad thing?

    View full-size slide

  31. TIp #2
    Code should talk to you

    View full-size slide

  32. _$ = (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)
    }
    }
    })({})

    View full-size slide

  33. _$ = (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

    View full-size slide

  34. _$ = (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);
    }
    };
    })();

    View full-size slide

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

    View full-size slide

  36. //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
    }

    View full-size slide

  37. //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

    View full-size slide

  38. //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

    View full-size slide

  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
    }
    un-avoidable
    hacks explanation
    AUTOMATED DOC
    GENERATION
    TODOs

    View full-size slide

  40. TIp #3
    Code should have 

    personal boundaries

    View full-size slide

  41. Define 

    boundaries

    View full-size slide

  42. Single
    responsibility
    principle
    your best tool
    against Zombie Code

    View full-size slide

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

    View full-size slide

  44. 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

    View full-size slide

  45. 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

    View full-size slide

  46. worst case smell

    View full-size slide

  47. worst case smell
    Long methods

    View full-size slide

  48. worst case smell
    Long methods
    Deep Level of Indentation

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  53. 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

    View full-size slide

  54. And now what?

    View full-size slide

  55. Basically
    Quarantine

    View full-size slide

  56. Basically
    Quarantine

    View full-size slide

  57. 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

    View full-size slide

  58. The broken window

    View full-size slide

  59. “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

    View full-size slide

  60. “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

    View full-size slide

  61. 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

    View full-size slide

  62. Isolate the Zombies

    View full-size slide

  63. define style guidelines

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  68. start linting your code

    View full-size slide

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

    View full-size slide

  70. start testing your code

    View full-size slide

  71. Unit or Functional?

    View full-size slide

  72. As long as it can be automated
    share
    identify
    build
    make it
    continuous

    View full-size slide

  73. Make it part of the process
    Make it part of the process

    View full-size slide

  74. 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/

    View full-size slide

  75. 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/

    View full-size slide

  76. 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/

    View full-size slide

  77. Fear the living? DON’T

    View full-size slide

  78. DEVOPS PRODUCT OWNER
    qa

    View full-size slide

  79. QA
    Crucial role in the
    process

    View full-size slide

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

    View full-size slide

  81. QA
    Crucial role in the
    process
    Quality should be your
    goal too
    Get help for functional
    test coverage not to
    screw up refactoring

    View full-size slide

  82. Devops
    The tough guy

    View full-size slide

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

    View full-size slide

  84. Devops
    The tough guy
    It could be hard to deal
    with
    Get help setting up the
    automated process

    View full-size slide

  85. Product owner

    View full-size slide

  86. Product owner
    The less interested in
    code itself

    View full-size slide

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

    View full-size slide

  88. Product owner
    The less interested in
    code itself
    Bring numbers, not
    theories
    Get help not wasting
    time, staying focused on
    functionalities

    View full-size slide

  89. Others in the company

    View full-size slide

  90. juniors
    external
    lobbyist

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  93. Juniors
    Pair with them, code
    review their (and your)
    code
    Involve them during the
    whole process definition
    Get help keeping things
    easy and accessible

    View full-size slide

  94. Learn to say NO!

    View full-size slide

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

    View full-size slide

  96. Learn to say NO!
    Lobbyists will slow you
    down, your brain will be
    more prone to be eaten
    Redirect them to the
    product owner

    View full-size slide

  97. Basically
    KILL ‘EM ALL (AGAIN?)

    View full-size slide

  98. Basically
    KILL ‘EM ALL (AGAIN?)

    View full-size slide

  99. KILL ‘EM ALL (AGAIN?)
    “Nothing is impossible to
    kill.”
    Mira Grant, Feed

    View full-size slide

  100. “Without requirements or design,
    programming is the art of adding bugs
    to an empty text file”
    Louis Srygley
    Design for your goal

    View full-size slide

  101. Design for your goal

    View full-size slide

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

    View full-size slide

  103. Modular Architecture

    View full-size slide

  104. Scalable JavaScript
    Application
    Architecture
    by Nicholas Zakas

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  110. 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');

    View full-size slide

  111. 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');

    View full-size slide

  112. 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');

    View full-size slide

  113. 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');

    View full-size slide

  114. 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');

    View full-size slide

  115. 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');

    View full-size slide

  116. Event Driven Pattern

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  119. sandbox.layer("an error occured");

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  132. Advantages
    DECOUPLING

    View full-size slide

  133. “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?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  139. //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;
    }
    };
    };
    });

    View full-size slide

  140. //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;
    }
    };
    };
    });

    View full-size slide

  141. //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;
    }
    };
    };
    });

    View full-size slide

  142. //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;
    }
    };
    };
    });

    View full-size slide

  143. //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;
    }
    };
    };
    });

    View full-size slide

  144. //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;
    }
    };
    };
    });

    View full-size slide

  145. //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;
    }
    };
    };
    });

    View full-size slide

  146. //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;
    }
    };
    };
    });

    View full-size slide

  147. //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;
    }
    };
    };
    });

    View full-size slide


  148. //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();
    })
    });

    View full-size slide


  149. //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();
    })
    });

    View full-size slide


  150. //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();
    })
    });

    View full-size slide


  151. //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();
    })
    });

    View full-size slide


  152. //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();
    })
    });

    View full-size slide

  153. Pulling all together

    View full-size slide

  154. 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
    }
    };
    };
    });

    View full-size slide

  155. 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
    }
    };
    };
    });

    View full-size slide

  156. 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
    }
    };
    };
    });

    View full-size slide

  157. 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
    }
    };
    };
    });

    View full-size slide

  158. 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
    }
    };
    };
    });

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  165. 2 years later…

    View full-size slide

  166. 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
    };

    View full-size slide

  167. 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

    View full-size slide

  168. import $ from 'jquery';
    import myscript from 'myscript';
    import anotherDep from 'anotherDep';
    // Do Something
    ES6

    View full-size slide

  169. No such thing!

    View full-size slide

  170. Basically
    Happy Endings?

    View full-size slide

  171. Basically
    Happy Endings?

    View full-size slide

  172. “If you want a happy ending, that
    depends, of course, on where you stop
    your story.”
    Orson Wells
    Happy ending

    View full-size slide

  173. You can run, you can hide

    View full-size slide

  174. You are going to
    SHITTY code
    anyway
    write

    View full-size slide

  175. You are going to
    write Zombie code
    anyway

    View full-size slide

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

    View full-size slide

  177. Don’t improvise

    View full-size slide

  178. Learn how to deal with it

    View full-size slide

  179. Until you master it

    View full-size slide

  180. in any case just
    remember to

    View full-size slide

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

    View full-size slide

  182. [email protected]
    http://cedmax.com
    @cedmax
    any question?

    View full-size slide