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

Learning to Fly — Twitter Flight and Mixins

Learning to Fly — Twitter Flight and Mixins

Presented at BrazilJS, Porto Alegre, August 22nd 2013

Angus Croll

August 23, 2013
Tweet

More Decks by Angus Croll

Other Decks in Technology

Transcript

  1. Learning to fly
    Twitter Flight and Mixins
    @angustweets
    Thursday, August 22, 13

    View Slide

  2. the most difficult part of JS inheritance...
    And on the 6th day, God created an
    abundance of Talking Animals, that
    they may be used in JavaScript
    inheritance examples.
    Thursday, August 22, 13

    View Slide

  3. So, talking animals it is!
    meow!!
    Thursday, August 22, 13

    View Slide

  4. Flight
    flightjs.github.io
    An event driven web framework by Twitter
    Thursday, August 22, 13

    View Slide

  5. Flight powers...
    twitter.com tweetdeck
    gumroad yinzcam
    crashalytics
    and more...
    Thursday, August 22, 13

    View Slide

  6. A set of components which bind functionality to
    DOM Nodes...
    Thursday, August 22, 13

    View Slide

  7. github.com/flightjs/example-app
    Thursday, August 22, 13

    View Slide

  8. github.com/flightjs/example-app
    Thursday, August 22, 13

    View Slide

  9. Components are completely decoupled and
    communicate via event bubbling
    Thursday, August 22, 13

    View Slide

  10. Thursday, August 22, 13

    View Slide

  11. Components often share behaviours
    Thursday, August 22, 13

    View Slide

  12. Components often share behaviours
    So we needed a re-use technique
    Thursday, August 22, 13

    View Slide

  13. Inheritance
    classical
    composition
    mixins
    Functions
    Object.create
    Constructor.prototype
    function passing / callbacks
    Objects
    call/apply
    functional mixins
    (Some) JavaScript Re-use Patterns
    Thursday, August 22, 13

    View Slide

  14. Inheritance
    classical
    composition
    mixins
    Functions
    Object.create
    Constructor.prototype
    function passing / callbacks
    Objects
    call/apply
    functional mixins
    (Some) JavaScript Re-use Patterns
    Thursday, August 22, 13

    View Slide

  15. Classical Inheritance
    Thursday, August 22, 13

    View Slide

  16. ES 6 is giving us class.
    Some libraries have their own versions.
    Thursday, August 22, 13

    View Slide

  17. implementation varies widely and abstraction is often
    leaky (const, static)
    class, extend and super are reserved words
    in particular, the relationship between this and super
    is difficult...
    Thursday, August 22, 13

    View Slide

  18. //Prototype.js
    var SwimmingAnimal = Class.create(Animal, {
    type: 'SwimmingAnimal',
    speak: function($super) {
    return $super() + ", glug";
    }
    });
    //https://github.com/ded/klass
    var Alien = SuperHuman.extend({
    speak: function() {
    this.supr();
    //speak like a SuperHuman
    }
    });
    Thursday, August 22, 13

    View Slide

  19. Do you even want classes?
    Thursday, August 22, 13

    View Slide

  20. Animal
    Walking Animal
    Swimming Animal
    Flying Animal
    Cat
    Elephant
    Crocodile
    Whale
    Eagle
    Bat
    Egg-laying Animal
    Migrating Animal
    Thursday, August 22, 13

    View Slide

  21. Crocodile
    Animal
    Walking Animal
    Swimming Animal
    Flying Animal
    Cat
    Elephant
    Whale
    Eagle
    Bat
    Egg-laying Animal
    Migrating Animal
    Thursday, August 22, 13

    View Slide

  22. Crocodile
    Animal
    Walking Animal
    Swimming Animal
    Flying Animal
    Cat
    Elephant
    Whale
    Eagle
    Bat
    Egg-laying Animal
    Migrating Animal
    WTF? I walk too!!
    Thursday, August 22, 13

    View Slide

  23. Animal
    Walking Animal
    Swimming Animal
    Flying Animal
    Cat
    Elephant
    Crocodile
    Whale
    Eagle
    Bat
    Egg-laying Animal
    Migrating Animal
    Thursday, August 22, 13

    View Slide

  24. Duck?
    Animal
    Walking Animal
    Swimming Animal
    Flying Animal
    Cat
    Elephant
    Crocodile
    Whale
    Eagle
    Bat
    Egg-laying Animal
    Migrating Animal
    Thursday, August 22, 13

    View Slide

  25. Duck?
    Animal
    Cat
    Elephant
    Crocodile
    Whale
    Eagle
    Bat
    Thursday, August 22, 13

    View Slide

  26. Duck?
    Animal
    Cat
    Elephant
    Crocodile
    Whale
    Eagle
    Bat
    Walking Animal
    Swimming Animal
    Flying Animal
    Egg-laying Animal
    Migrating Animal
    Thursday, August 22, 13

    View Slide

  27. Classical inheritance
    Requires up-front knowledge of general case
    Single rooted hierarchy
    We’re really bad at classification
    Thursday, August 22, 13

    View Slide

  28. Constructor.prototype chaining
    Thursday, August 22, 13

    View Slide

  29. awkward and unnatural
    Thursday, August 22, 13

    View Slide

  30. var Animal = function(gender, says) {
    this.gender = gender;
    this.says = says;
    };
    var WalkingAnimal = function(gender, says) {
    Animal.call(this, gender, says);
    }
    WalkingAnimal.prototype = new Animal();
    Thursday, August 22, 13

    View Slide

  31. ...and new Constructor syntax
    is classical inheritance
    Thursday, August 22, 13

    View Slide

  32. Beyond classification...
    Thursday, August 22, 13

    View Slide

  33. 19th century British philosophers Whewell and
    Jevons argued that there are no objectively
    “right” classifications
    Thursday, August 22, 13

    View Slide

  34. “In general, when working with prototypes, one
    typically chooses not to categorize but to
    exploit alikeness.”
    –Antero Taivalsaari (Nokia Research Center)
    Thursday, August 22, 13

    View Slide

  35. liberates prototype chaining from classification
    Object.create
    Thursday, August 22, 13

    View Slide

  36. var animalProto = {
    speak: function() {
    console.log(this.says);
    }
    }
    var walkingAnimalProto = Object.create(animalProto);
    // then augment walkingAnimalProto here...
    Thursday, August 22, 13

    View Slide

  37. but, that second argument
    :’’(
    Thursday, August 22, 13

    View Slide

  38. var animalProto = {
    speak: function() {
    console.log(this.says);
    }
    }
    var walkingAnimalProto = Object.create(
    animalProto, {
    walk: {
    value: function() {
    console.log('walking');
    }
    }
    //...
    }
    );
    Thursday, August 22, 13

    View Slide

  39. and inheritance is still single rooted
    Thursday, August 22, 13

    View Slide

  40. The sad thing is that we even care about inheritance
    hierarchies...
    Thursday, August 22, 13

    View Slide

  41. The sad thing is that we even care about inheritance
    hierarchies...
    ...because in JavaScript they’re quite unnecessary...
    Thursday, August 22, 13

    View Slide

  42. JavaScript has first class functions
    Any function can be assigned to any object
    Thursday, August 22, 13

    View Slide

  43. Mixins
    Thursday, August 22, 13

    View Slide

  44. //A property copy mixin
    var withWalking = {
    walk: function() {
    console.log('walking');
    },
    turn: function(direction) {
    console.log('turning', direction);
    },
    stopWalking: function() {
    console.log('stopped walking');
    }
    };
    Thursday, August 22, 13

    View Slide

  45. var extend = function(destination, source) {
    for (var k in source) {
    if (source.hasOwnProperty(k)) {
    destination[k] = source[k];
    }
    }
    return destination;
    };
    extend(Crocodile.prototype, withWalking);
    extend(Crocodile.prototype, withSwimming);
    Thursday, August 22, 13

    View Slide

  46. No hierarchical constraints
    Functionality is grouped by what it does not
    who it belongs to
    Define special cases first; common code later
    Thursday, August 22, 13

    View Slide

  47. Mixin must know about target
    Properties can only clobber
    But...
    Thursday, August 22, 13

    View Slide

  48. Functional Mixins
    Thursday, August 22, 13

    View Slide

  49. var withWalking = function() {
    this.walk = function() {
    console.log('walking');
    };
    this.turn = function(direction) {
    console.log('turning', direction);
    };
    this.stopWalking = function() {
    console.log('stopped walking');
    };
    };
    Thursday, August 22, 13

    View Slide

  50. function Crocodile(name, gender) {
    this.name = name;
    this.gender = gender;
    }
    Crocodile.prototype.stalkTourists = function() {
    //..
    };
    withWalking.call(Crocodile.prototype);
    withSwimming.call(Crocodile.prototype);
    Thursday, August 22, 13

    View Slide

  51. Flight uses functional mixins
    Thursday, August 22, 13

    View Slide

  52. github.com/flightjs/example-app
    Thursday, August 22, 13

    View Slide

  53. function withSelect() {
    this.defaultAttrs({
    selectedIds: []
    });
    this.selectItem = function($item, append) {
    $item.addClass(this.attr.selectedClass);
    this.attr.selectedIds.push($item.attr('id'));
    this.trigger('uiSelectionChanged', {selIds: this.attr.selectedIds});
    };
    this.unselectItem = function($item) {
    $item.removeClass(this.attr.selectedClass);
    this.attr.selectedIds.splice(getIdIndex($item), 1);
    this.trigger('uiSelectionChanged', {selIds: this.attr.selectedIds});
    };
    }
    Thursday, August 22, 13

    View Slide

  54. defineComponent(mailItems, withSelect);
    defineComponent(folders, withSelect);
    defineComponent(moveToSelector, withSelect);
    Thursday, August 22, 13

    View Slide

  55. The Advice Mixin
    Thursday, August 22, 13

    View Slide

  56. advice.js is a mixin
    Thursday, August 22, 13

    View Slide

  57. advice.js is a mixin
    it lets you add custom code before(), after() or
    around() an existing function.
    Thursday, August 22, 13

    View Slide

  58. all flight mixins get advice.js for free
    Thursday, August 22, 13

    View Slide

  59. all flight mixins get advice.js for free
    so mixins can augment functions, not clobber them
    Thursday, August 22, 13

    View Slide

  60. withAdvice.call(Crocodile.prototype);
    function withFlu() {
    this.before('walk', function() {
    console.log('sniff');
    });
    }
    var sickCrocodile = new Crocodile();
    withFlu.call(sickCrocodile);
    sickCrocodile.walk();
    //"sniff, pad, pad, pad, pad"
    Thursday, August 22, 13

    View Slide

  61. function withSelect() {
    this.defaultAttrs({
    selectedIds: []
    });
    this.toggleItemSelect = function(ev, data) {
    var $item = $(data.el), append;
    if ($item.hasClass(this.attr.selectedClass)) {
    this.unselectItem($item);
    } else {
    this.selectItem($item, isMultiSelect(ev));
    }
    };
    this.selectItem = function($item, append) {/*..*/};
    this.unselectItem = function($item) {/*..*/};
    this.after('initialize', function() {
    this.on(this.select('itemSelector'), 'click', this.toggleItemSelect);
    });
    }
    Thursday, August 22, 13

    View Slide

  62. So why do we like functional mixins?
    Thursday, August 22, 13

    View Slide

  63. Mixins as verbs instead of nouns.
    Mixins are functions. We can take advantage of
    closure scope and arguments.
    A mixin can be applied to any object type: prototype,
    instance, whatever.
    Advice allows functional mixins to augment existing
    functions, not clobber them.
    Thursday, August 22, 13

    View Slide

  64. Works with the language
    Simple to understand
    No surprises!
    Thursday, August 22, 13

    View Slide

  65. Obrigado!
    @angustweets
    javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-
    javascript-mixins/
    Thursday, August 22, 13

    View Slide