$30 off During Our Annual Pro Sale. View Details »

Zombie Code - Dibi London 2016

Zombie Code - Dibi London 2016

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?

Marco has been there and he’s a survivor because he learnt the art of refactoring.
In this talk he’ll share lessons learnt about how to deal with features request, deadlines and still increase the maintainability of your code.

Marco Cedaro

October 21, 2016
Tweet

More Decks by Marco Cedaro

Other Decks in Technology

Transcript

  1. TALK

    View Slide

  2. Zombie Code
    London
    21st October

    View Slide

  3. First things first
    my name is
    @cedmax

    View Slide

  4. cedmax @ Kahoot!

    View Slide

  5. Basically
    Zombies?

    View Slide

  6. Basically
    Zombies?

    View Slide

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

    View Slide

  8. ZOMBIE CODE?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. during estimation

    View Slide

  14. during debugging

    View Slide

  15. during development

    View Slide

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

    View Slide

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

    View Slide

  18. There isn’t a recipe
    https://www.etsy.com/listing/224941057/zombie-cure-pill-case-7-sections-pill

    View Slide

  19. How to identify
    Zombie CODE?

    View Slide

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

    View Slide

  21. TIp #1
    Code should be appealing

    View Slide

  22. 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 Slide

  23. // 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 Slide

  24. 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 Slide

  25. - A very long method

    View Slide

  26. 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 Slide

  27. // 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 Slide

  28. 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 Slide

  29. - 14 (FOURTEEN!) if statements

    View Slide

  30. 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 Slide

  31. // 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 Slide

  32. 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 Slide

  33. - nested function definitions

    View Slide

  34. 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 Slide

  35. // 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 Slide

  36. 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 Slide

  37. - deep level of indentation

    View Slide

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

  39. // 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 Slide

  40. 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 Slide

  41. HOLD ON THERE!

    are comments a bad thing?

    View Slide

  42. TIp #2
    Code should talk to you

    View Slide

  43. var PubSub = ((_) => ({
    pub:(a, b, c, d) => {
    for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)
    },
    sub:(a, b) => {
    (_[a] || (_[a] = [])).push(b)
    }
    }))({})

    View Slide

  44. var PubSub = ((_) => ({
    pub:(a, b, c, d) => {
    for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)
    },
    sub:(a, b) => {
    (_[a] || (_[a] = [])).push(b)
    }
    }))({})
    #140bytes

    View Slide

  45. var PubSub = (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 Slide

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

    View Slide

  47. //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 Slide

  48. //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 Slide

  49. //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 Slide

  50. //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 Slide

  51. TIp #3
    Code should have 

    personal boundaries

    View Slide

  52. Define 

    boundaries

    View Slide

  53. Single
    responsibility
    principle
    your best tool
    against Zombie Code

    View Slide

  54. 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 Slide

  55. worst case smell

    View Slide

  56. worst case smell
    Long methods

    View Slide

  57. worst case smell
    Long methods
    Deep Level of Indentation

    View Slide

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

    View Slide

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

    View Slide

  60. worst case smell
    Long methods
    Deep Level of Indentation
    Hard to tell what it does
    Lack of portability
    Copy/paste driven development

    View Slide

  61. worst case smell
    Long methods
    Deep Level of Indentation
    Hard to tell what it does
    Lack of portability
    Copy/paste driven development
    Callback hell

    View Slide

  62. And now what?

    View Slide

  63. Play cool!

    View Slide

  64. Basically
    Quarantine

    View Slide

  65. Basically
    Quarantine

    View Slide

  66. 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 Slide

  67. The broken window

    View Slide

  68. “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 Slide

  69. “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 Slide

  70. 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 Slide

  71. Isolate the Zombies

    View Slide

  72. define a styleguide
    http://alistapart.com/article/creating-style-guides

    View Slide

  73. …and enforce it

    View Slide

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

    View Slide

  75. start testing your code

    View Slide

  76. Both Unit or Functional

    View Slide

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

    View Slide

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

    View Slide

  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/

    View Slide

  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/

    View Slide

  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/

    View Slide

  82. Fear the living? DON’T

    View Slide

  83. The team

    View Slide

  84. PRODUCT
    OWNER DevOPS
    qa

    View Slide

  85. Quality Assurance

    View Slide

  86. Quality Assurance
    Crucial role in the
    process

    View Slide

  87. Quality Assurance
    Crucial role in the
    process
    You share the same goals

    View Slide

  88. Quality Assurance
    Crucial role in the
    process
    You share the same goals
    Get help for functional
    tests, they are a drain!

    View Slide

  89. Devops

    View Slide

  90. Devops
    The tough one

    View Slide

  91. Devops
    The tough one
    It could be hard to deal
    with

    View Slide

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

    View Slide

  93. Product owner

    View Slide

  94. Product owner
    The less interested in
    code itself

    View Slide

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

    View Slide

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

    View Slide

  97. Others in the company

    View Slide

  98. juniors
    external
    lobbyist

    View Slide

  99. Juniors

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  103. Learn to say NO!

    View Slide

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

    View Slide

  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

    View Slide

  106. Basically
    KILL ‘EM ALL (AGAIN?)

    View Slide

  107. Basically
    KILL ‘EM ALL (AGAIN?)

    View Slide

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

    View Slide

  109. but

    View Slide

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

    View Slide

  111. Design for your goal

    View Slide

  112. Modular Architecture

    View Slide

  113. View Slide

  114. Scalable JavaScript
    Application
    Architecture
    by Nicholas Zakas

    circa 2009

    View Slide

  115. View Slide

  116. View Slide

  117. core.register("module-name",(sandbox) => {
    init: function() {
    },
    destroy: function() {
    }
    });

    View Slide

  118. core.register("module-name",(sandbox) => {
    init: function() {
    },
    destroy: function() {
    }
    });

    View Slide

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

    View Slide

  120. View Slide

  121. View Slide

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

    View Slide

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

    View Slide

  124. View Slide

  125. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  126. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  127. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  128. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  129. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  130. core.register(‘module-name', (sandbox) => {
    init: function(config) {
    console.log(config.id);
    }
    });
    core.configure('module-name', {
    id: 'container',
    });
    core.start('module-name');
    core.stop('module-name');

    View Slide

  131. View Slide

  132. View Slide

  133. Event Driven Pattern

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  149. Advantages
    DECOUPLING

    View Slide

  150. Flux

    circa 2014

    View Slide

  151. Flux

    View Slide

  152. Flux
    I can walk you through it

    View Slide

  153. Flux
    A kind of usual feature

    View Slide

  154. Flux
    The user triggers an event…

    View Slide

  155. onFollowButtonClick(user) {
    actionCreators.followButtonClicked({
    user
    });
    }
    …and an event handler kicks in
    Flux

    View Slide

  156. onFollowButtonClick(user) {
    actionCreators.followButtonClicked({
    user
    });
    }
    …and an event handler kicks in
    Flux

    View Slide

  157. Flux
    Here comes the action

    View Slide

  158. followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }
    Let’s have a look at the action creator
    Flux

    View Slide

  159. followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }
    The created action has a type and a data prop
    Flux

    View Slide

  160. followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }
    Where the type is an identifier
    Flux

    View Slide

  161. followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }
    The action could depend on a network call
    Flux

    View Slide

  162. followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }
    It gets sent to the dispatcher
    Flux

    View Slide

  163. Flux
    The dispatcher is where the magic happens

    View Slide

  164. Let’s dumb it down
    Flux
    followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }

    View Slide

  165. Let’s dumb it down
    Flux
    followButtonClicked({ user }) {
    APIClient.followUser(user.uuid)
    .then(() => {
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });
    });
    }

    View Slide

  166. Doesn’t it look like…
    Flux
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });

    View Slide

  167. a pub sub!
    Flux
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });


    pubSub.publish(
    actionTypes.userFollowed,
    { user }
    );

    View Slide

  168. Flux
    dispatcher.handleAction({
    type: actionTypes.userFollowed,
    data: { user }
    });


    pubSub.publish(
    actionTypes.userFollowed,
    { user }
    );
    As a matter of fact it is

    View Slide

  169. Flux
    And the store is subscribed to it

    View Slide

  170. Flux
    The store is where your business logic lives

    View Slide

  171. export default {
    [actionTypes.userFollowed]: function({ data }) {

    //MAGIC to define the new followers list

    this.updateState({
    user: {
    followers
    }
    });

    this.emitChange();
    }
    }
    Please test your magic
    Flux

    View Slide

  172. export default {
    [actionTypes.userFollowed]: function({ data }) {

    //MAGIC to define the new followers list

    this.updateState({
    user: {
    followers
    }
    });

    this.emitChange();
    }
    }
    The store updates the model…
    Flux

    View Slide

  173. export default {
    [actionTypes.userFollowed]: function({ data }) {

    //MAGIC to define the new followers list

    this.updateState({
    user: {
    followers
    }
    });

    this.emitChange();
    }
    }
    …and it emits the change
    Flux

    View Slide

  174. Which would trigger the view to update
    Flux

    View Slide

  175. Want to unfollow?
    Flux

    View Slide

  176. Here we go again
    Flux

    View Slide

  177. “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 Slide

  178. No such thing!

    View Slide

  179. Basically
    Happy Endings?

    View Slide

  180. Basically
    Happy Endings?

    View Slide

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

    View Slide

  182. You can run, you can hide

    View Slide

  183. You are going to
    SHITTY code
    anyway
    write

    View Slide

  184. You are going to
    write Zombie code
    anyway

    View Slide

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

    View Slide

  186. Don’t improvise

    View Slide

  187. Learn how to deal with it

    View Slide

  188. Until you master it

    View Slide

  189. Just remember to

    View Slide

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

    View Slide

  191. View Slide

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

    View Slide