KEMBAR78
SWDC 2010: Programming to Patterns | PDF
Programming To
                          Patterns
                           Dylan Schiemann
                          (SitePen and Dojo)




                          SWDC, June 2, 2010

Sunday, May 30, 2010
Patterns?
                 • Abstraction is the key
                 • Focus less on the implementation at
                       hand and more on the code

                 • Think in terms of an API
                 • Imagine using it somewhere else
                 • Write granular, atomic components
                 • Use Test Driven Development
Sunday, May 30, 2010
Example 1: The
                       Namespaced Library




Sunday, May 30, 2010
Example 1: The
                       Namespaced Library
                              Classes
                              DatePicker
                             FormValidator
                                   Fx
                                Request
                               Slideshow
                                  etc...




Sunday, May 30, 2010
Example 1: The
                       Namespaced Library
       var myApp = {
         init: function(){
          myApp.apples()
          myApp.orange()                                         Classes
          myApp.lemons()                                         DatePicker
        },                                                      FormValidator
        apples: function(){                                           Fx
          $$(‘div.apple’).each(function(apple) {                   Request
             var form = apple.getElement(‘form’);                 Slideshow
             form.addEvent(‘submit’, function(event){ ....});        etc...
          });
        },
        orange: function(){
          $(‘orange’).getElements(‘li’).each...
        },
         etc...




Sunday, May 30, 2010
Example 1: The
                       Namespaced Library
       var myApp = {
         init: function(){
          myApp.apples()
          myApp.orange()                                         Classes
          myApp.lemons()                                         DatePicker
        },                                                      FormValidator
        apples: function(){                                           Fx
          $$(‘div.apple’).each(function(apple) {                   Request
             var form = apple.getElement(‘form’);                 Slideshow
             form.addEvent(‘submit’, function(event){ ....});        etc...
          });
        },
        orange: function(){
          $(‘orange’).getElements(‘li’).each...
        },
         etc...


                              This tends to get out of hand
Sunday, May 30, 2010
Banging it out...
              <script>dojo.ready(function() {
                  dojo.connect(dojo.byId('myForm'), 'onsubmit', function(evt){
                       dojo.stopEvent(evt);
                       var formNode = evt.target;
                       dojo.xhrPost({
                        form: formNode,
                        url: formNode.action,
                        handle: function(response, ioArgs){
                              dojo.byId('myContainer').innerHTML = response;
                          }
               });});});
              </script>



                        This is very tempting.
Sunday, May 30, 2010
Pros
                • Writing the logic for a specific app is fast
                       and furious

                • The test environment is the app




Sunday, May 30, 2010
Pros
                • Writing the logic for a specific app is fast
                       and furious

                • The test environment is the app
                                     & Cons
              • It’s much harder to maintain
              • A high percentage of code you write for the
                       app isn’t reusable

              • The test environment is the app

Sunday, May 30, 2010
What to do?

                • Objects; stateful objects
                • Some people think of these as “Classes”
                • This is how JavaScript itself solves these
                       problems

                • Most toolkits/frameworks help you do this



Sunday, May 30, 2010
`




Sunday, May 30, 2010
`
              This is how
            MooTools does it
             var Human = new Class({
                 isAlive: true,
                 energy: 1,
                 eat: function(){
                     this.energy++;
                 }
             });




                                       Human




Sunday, May 30, 2010
`
              This is how
            MooTools does it
             var Human = new Class({
                 isAlive: true,
                 energy: 1,
                 eat: function(){
                     this.energy++;
                 }
             });


             var bob = new Human();
             //bob.energy === 1

             bob.eat();
             //bob.energy === 2




                                       Human




                                                   bob
Sunday, May 30, 2010
`
              This is how                         This is how
            MooTools does it                      Dojo does it
             var Human = new Class({       dojo.declare("Human",
                 isAlive: true,               null, {
                 energy: 1,                     isAlive: true,
                 eat: function(){               energy: 1,
                     this.energy++;             eat: function(){
                 }                                  this.energy++;
             });                                }
                                              }
                                           );
             var bob = new Human();
             //bob.energy === 1
                                           var bob = new Human();
             bob.eat();                    //bob.energy === 1
             //bob.energy === 2
                                           bob.eat();
                                           //bob.energy === 2




Sunday, May 30, 2010
Prototypes




Sunday, May 30, 2010
Prototypes
          var humanBase = {
             isAlive: true,
             energy: 1,
             eat: function(){
               this.energy++;
             }
          };




               humanBase



          object (our prototype)




Sunday, May 30, 2010
Prototypes
          var humanBase = {        //MooTools
             isAlive: true,        var Human =
             energy: 1,              new Class(humanBase);
             eat: function(){
               this.energy++;      //Dojo
             }                     dojo.declare(“Human”,
          };                         null, humanBase);




               humanBase                  Human



          object (our prototype)    Function (constructor)




Sunday, May 30, 2010
Prototypes
          var humanBase = {        //MooTools
             isAlive: true,        var Human =
             energy: 1,              new Class(humanBase);   //MooTools & Dojo
             eat: function(){                                var bob = new Human()
               this.energy++;      //Dojo
             }                     dojo.declare(“Human”,
          };                         null, humanBase);




               humanBase                  Human                        bob



          object (our prototype)    Function (constructor)     object (our instance)




Sunday, May 30, 2010
Prototypes
                                                                                             energy ==
                              energy == 1
              humanBase                           Human                      bob             undefined




          object (our prototype)            Function (constructor)   object (our instance)




             bob.energy == Human.prototype.energy




Sunday, May 30, 2010
Prototypes
                                                                                                energy ==
                              energy == 1
              humanBase                           Human                         bob             undefined




          object (our prototype)            Function (constructor)      object (our instance)




             bob.energy == Human.prototype.energy

              bob.foo == undefined //bob.foo AND Human.prototype.foo are not found




Sunday, May 30, 2010
Prototypes
                                                                                                energy ==
                              energy == 1
              humanBase                           Human                         bob             undefined




                                                                                                foo == “bar”
          object (our prototype)            Function (constructor)      object (our instance)




             bob.energy == Human.prototype.energy

              bob.foo == undefined //bob.foo AND Human.prototype.foo are not found

              bob.foo = “bar” //bob has a “foo” property, the prototype is not checked




Sunday, May 30, 2010
Prototypes
                              energy == 1                                                       energy == 2
              humanBase                           Human                         bob


                                                                                                foo == “bar”
          object (our prototype)            Function (constructor)      object (our instance)




             bob.energy == Human.prototype.energy

              bob.foo == undefined //bob.foo AND Human.prototype.foo are not found

              bob.foo = “bar” //bob has a “foo” property, the prototype is not checked

              bob.eat() //assigns a value to bob.energy; Human.prototype.energy is no
                        //longer checked




Sunday, May 30, 2010
Extending Classes
                            (MooTools)




Sunday, May 30, 2010
Extending Classes
                                          (MooTools)

   var Human = new Class({
       initialize: function(name, age){
           this.name = name;
           this.age = age;
       },
       isAlive: true,
       energy: 1,
       eat: function(){
           this.energy++;
       }
   });




Sunday, May 30, 2010
Extending Classes
                                          (MooTools)

   var Human = new Class({                   var Ninja = new Class({
       initialize: function(name, age){        Extends: Human,
           this.name = name;                   initialize: function(side, name, age){
           this.age = age;                        this.side = side;
       },                                         this.parent(name, age);
       isAlive: true,                          },
       energy: 1,                              energy: 100,
       eat: function(){                        attack: function(target){
           this.energy++;                         this.energy = this.energy - 5;
       }                                          target.isAlive = false;
   });                                         }
                                             });




Sunday, May 30, 2010
Extending Classes
                                          (MooTools)

   var Human = new Class({                   var Ninja = new Class({
       initialize: function(name, age){        Extends: Human,
           this.name = name;                   initialize: function(side, name, age){
           this.age = age;                        this.side = side;
       },                                         this.parent(name, age);
       isAlive: true,                          },
       energy: 1,                              energy: 100,
       eat: function(){                        attack: function(target){
           this.energy++;                         this.energy = this.energy - 5;
       }                                          target.isAlive = false;
   });                                         }
                                             });




Sunday, May 30, 2010
Extending Classes
                                          (MooTools)

   var Human = new Class({                      var Ninja = new Class({
       initialize: function(name, age){           Extends: Human,
           this.name = name;                      initialize: function(side, name, age){
           this.age = age;                           this.side = side;
       },                                            this.parent(name, age);
       isAlive: true,                             },
       energy: 1,                                 energy: 100,
       eat: function(){                           attack: function(target){
           this.energy++;                            this.energy = this.energy - 5;
       }                                             target.isAlive = false;
   });                                            }
                                                });


                              var bob = new Human('Bob', 25);




Sunday, May 30, 2010
Extending Classes
                                          (MooTools)

   var Human = new Class({                      var Ninja = new Class({
       initialize: function(name, age){           Extends: Human,
           this.name = name;                      initialize: function(side, name, age){
           this.age = age;                           this.side = side;
       },                                            this.parent(name, age);
       isAlive: true,                             },
       energy: 1,                                 energy: 100,
       eat: function(){                           attack: function(target){
           this.energy++;                            this.energy = this.energy - 5;
       }                                             target.isAlive = false;
   });                                            }
                                                });


                              var bob = new Human('Bob', 25);


                             var blackNinja =
                               new Ninja('evil', 'Nin Tendo', 'unknown');
                             //blackNinja.isAlive = true
                             //blackNinja.name = 'Nin Tendo'

                             blackNinja.attack(bob);
                             //bob never had a chance




Sunday, May 30, 2010
Extending Classes
                             (Dojo)




Sunday, May 30, 2010
Extending Classes
                                       (Dojo)

   dojo.declare("Human", null, {
     constructor: function(kwArgs) {
        dojo.mixin(this, kwArgs);
     },
     isAlive: true,
     energy: 1,
     eat: function(){
        this.energy++;
     }
   });




Sunday, May 30, 2010
Extending Classes
                                       (Dojo)

   dojo.declare("Human", null, {        dojo.declare(“Ninja”, Human,
     constructor: function(kwArgs) {       {
        dojo.mixin(this, kwArgs);            // Auto constructor inheritance
     },                                      energy: 100,
     isAlive: true,                          attack: function(target){
     energy: 1,                                this.energy = this.energy - 5;
     eat: function(){                          target.isAlive = false;
        this.energy++;                       }
     }                                  );
   });




Sunday, May 30, 2010
Extending Classes
                                       (Dojo)

   dojo.declare("Human", null, {        dojo.declare(“Ninja”, Human,
     constructor: function(kwArgs) {       {
        dojo.mixin(this, kwArgs);            // Auto constructor inheritance
     },                                      energy: 100,
     isAlive: true,                          attack: function(target){
     energy: 1,                                this.energy = this.energy - 5;
     eat: function(){                          target.isAlive = false;
        this.energy++;                       }
     }                                  );
   });




Sunday, May 30, 2010
Extending Classes
                                              (Dojo)

   dojo.declare("Human", null, {                dojo.declare(“Ninja”, Human,
     constructor: function(kwArgs) {               {
        dojo.mixin(this, kwArgs);                    // Auto constructor inheritance
     },                                              energy: 100,
     isAlive: true,                                  attack: function(target){
     energy: 1,                                        this.energy = this.energy - 5;
     eat: function(){                                  target.isAlive = false;
        this.energy++;                               }
     }                                          );
   });




                       var bob = new Human({name:'Bob', age: 25});




Sunday, May 30, 2010
Extending Classes
                                              (Dojo)

   dojo.declare("Human", null, {                dojo.declare(“Ninja”, Human,
     constructor: function(kwArgs) {               {
        dojo.mixin(this, kwArgs);                    // Auto constructor inheritance
     },                                              energy: 100,
     isAlive: true,                                  attack: function(target){
     energy: 1,                                        this.energy = this.energy - 5;
     eat: function(){                                  target.isAlive = false;
        this.energy++;                               }
     }                                          );
   });




                       var bob = new Human({name:'Bob', age: 25});


                             var blackNinja =
                               new Ninja({side:'evil', name:'Nin Tendo', age:'unknown'});
                             //blackNinja.isAlive = true
                             //blackNinja.name = 'Nin Tendo'

                             blackNinja.attack(bob);
                             //bob never had a chance




Sunday, May 30, 2010
Mixins with Dojo




Sunday, May 30, 2010
Mixins with Dojo
        dojo.declare(“Human”, null, {
          constructor: function(kwArgs) {
             dojo.mixin(this, kwArgs);
          },
          isAlive: true,
          energy: 1,
          eat: function(){
             this.energy++;
          }
        });




Sunday, May 30, 2010
Mixins with Dojo
        dojo.declare(“Human”, null, {
          constructor: function(kwArgs) {
             dojo.mixin(this, kwArgs);
          },
          isAlive: true,
          energy: 1,
          eat: function(){
             this.energy++;
          }
        });


        dojo.declare(“Warrior”, null, {
          energy: 100,
          kills: 0,
          attack: function(target){
            if (target.energy < this.energy) {
               target.isAlive = false;
               this.kills++;
            }
            this.energy = this.energy - 5;
          }
        });




Sunday, May 30, 2010
Mixins with Dojo
        dojo.declare(“Human”, null, {            dojo.declare(“Ninja”, [Human, Warrior], {
          constructor: function(kwArgs) {        });
             dojo.mixin(this, kwArgs);
          },
          isAlive: true,
          energy: 1,
          eat: function(){
             this.energy++;
          }
        });
                                                 dojo.declare(“Samurai”, [Human, Warrior], {
                                                   side: 'good',
        dojo.declare(“Warrior”, null, {            energy: 1000
          energy: 100,                           });
          kills: 0,
          attack: function(target){
            if (target.energy < this.energy) {
               target.isAlive = false;
               this.kills++;
            }
            this.energy = this.energy - 5;
          }
        });




Sunday, May 30, 2010
Mixins with MooTools




Sunday, May 30, 2010
Mixins with MooTools
        var Human = new Class({
          initialize: function(name, age){
             this.name = name;
             this.age = age;
          },
          isAlive: true,
          energy: 1,
          eat: function(){
             this.energy++;
          }
        });




Sunday, May 30, 2010
Mixins with MooTools
        var Human = new Class({
          initialize: function(name, age){
             this.name = name;
             this.age = age;
          },
          isAlive: true,
          energy: 1,
          eat: function(){
             this.energy++;
          }
        });

        var Warrior = new Class({
          energy: 100,
          kills: 0,
          attack: function(target){
            if (target.energy < this.energy) {
               target.isAlive = false;
               this.kills++;
            }
            this.energy = this.energy - 5;
          }
        });




Sunday, May 30, 2010
Mixins with MooTools
        var Human = new Class({                  var Ninja = new Class({
          initialize: function(name, age){         Extends: Human,
             this.name = name;                     Implements: [Warrior],
             this.age = age;                       initialize: function(side, name, age){
          },                                         this.side = side;
          isAlive: true,                             this.parent(name, age);
          energy: 1,                               }
          eat: function(){                       });
             this.energy++;
          }
        });

        var Warrior = new Class({                var Samurai = new Class({
          energy: 100,                             Extends: Human,
          kills: 0,                                Implements: [Warrior],
          attack: function(target){                side: 'good',
            if (target.energy < this.energy) {     energy: 1000
               target.isAlive = false;           });
               this.kills++;
            }
            this.energy = this.energy - 5;
          }
        });




Sunday, May 30, 2010
When to write a class...




Sunday, May 30, 2010
When to write a class...




Sunday, May 30, 2010
When to write a class...




Sunday, May 30, 2010
When to write a class...




Sunday, May 30, 2010
When to write a class...




Sunday, May 30, 2010
Best Practices




Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.




Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.
                • Break up logic into small methods.




Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.
                • Break up logic into small methods.
                • Break up functionality into small classes.




Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.
                • Break up logic into small methods.
                • Break up functionality into small classes.
                • Build ‘controller’ classes for grouped
                       functionality.




Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.
                • Break up logic into small methods.
                • Break up functionality into small classes.
                • Build ‘controller’ classes for grouped
                       functionality.

                • Use options and events liberally.



Sunday, May 30, 2010
Best Practices
                • Shallow inheritance works best.
                • Break up logic into small methods.
                • Break up functionality into small classes.
                • Build ‘controller’ classes for grouped
                       functionality.

                • Use options and events liberally.
                • Don’t be afraid to refactor, but avoid
                       breaking the interface.

Sunday, May 30, 2010
Let’s look at that earlier example again
              <script>dojo.ready(function() {
                  dojo.connect(dojo.byId('myForm'), 'onsubmit',function(evt){
                  dojo.stopEvent(evt);
                  var formNode = evt.target;
                  dojo.xhrPost({
                       form: formNode,
                       url: formNode.action,
                       handle: function(response, ioArgs){
                        dojo.byId('myContainer').innerHTML = response;
                       }
               });});});




Sunday, May 30, 2010
And here's the MooTools version
              <script>window.addEvent(‘domready’, function(){
                  $(‘myForm’).addEvent(‘submit’, function(evt){
                       evt.preventDefault();
                       this.set(‘send’, {
                        onComplete: function(result){
                             $(‘myContainer’).set(‘html’, result);
                        }
                       });
                       this.send();
                  });
              });</script>




Sunday, May 30, 2010
Program a Pattern
          var FormUpdater = new Class({
            initialize: function(form, container, options) {
              this.form = $(form);
              this.container = $(container);
              this.request = new Request(options);
              this.request.addEvent(‘success’,this.onComplete.bind(this));
              this.attach();
            },
            attach: function(){
              this.form.addEvent(‘submit’,this.send.bind(this));
            },
            send: function(evt){
              if (evt) evt.preventDefault();
              this.request.send({
                url: this.form.get(‘action’),
                data: this.form
              });
            },
            onComplete: function(responseTxt){
                this.container.set(‘html’, responseTxt);
            }
          });
          new FormUpdater($(‘myForm’), $(‘myContainer’));


Sunday, May 30, 2010
...and the Dojo Version
               dojo.declare(‘foo.FormUpdater’, null, {
               	 constructor: function(form, container, options) {
               	 	 this.form = form;
               	 	 this.container = container;
               	 	 this.requestOptions = options;
               	 	 this.attach();
               	 },
               	 attach: function(){
               
 
 dojo.connect(this.form, ‘onsubmit’, this ‘send’);
               	 },
               	 send: function(evt){
               	 	 if(evt) dojo.stopEvent(evt);
                      dojo.xhrPost(dojo.mixin({
                 	 	      form: this.form,
               	 	 	 url: this.form.action,
               	 	 	 handle: dojo.hitch(this, "onComplete")
               	 	 }, this.requestOptions));
               	 },
               	 onComplete: function(data){
               
 
 dojo.attr(this.container, ‘innerHTML’, data);
               	 }
               });
               new foo.FormUpdater(dojo.byId(‘myForm’),
                                       dojo.byId(‘myContainer’));
Sunday, May 30, 2010
And then extend it...
      dojo.declare(“foo.FormUpdater.Append”, FormUpdater, {
       onComplete: function(data){
          dojo.create(‘p’, {innerHTML: data}, this.container);
       }
      });
      new foo.FormUpdater.Append(dojo.byId(‘myForm’),
        dojo.byId(‘myTarget’));




Sunday, May 30, 2010
The MooTools version...
      var FormUpdater.Append = new Class({
       Extends: FormUpdater,
       onComplete: function(responseTxt){
          this.container.adopt(
            new Element(‘div’, {html: responseTxt})
          );
       }
      });
      new FormUpdater.Append($(‘myForm’), $(‘myTarget’));




Sunday, May 30, 2010
Developing with Class




Sunday, May 30, 2010
Developing with Class
       var myApp = {
         init: function(){
          myApp.apples()                      Classes
          myApp.orange()                      DatePicker
          myApp.lemons()                     FormValidator
        },                                         Fx
        apples: function(){                     Request
          new AppleGroup($$(‘div.apple’));     Slideshow
        },                                       Apple
        orange: function(){                   AppleGroup
          new Orange($(‘orange’)                Orange
        },                                        etc...
         etc...




Sunday, May 30, 2010
Developing with Class
       var myApp = {
         init: function(){
          myApp.apples()                              Classes
          myApp.orange()                              DatePicker
          myApp.lemons()                             FormValidator
        },                                                 Fx
        apples: function(){                             Request
          new AppleGroup($$(‘div.apple’));             Slideshow
        },                                               Apple
        orange: function(){                           AppleGroup
          new Orange($(‘orange’)                        Orange
        },                                                etc...
         etc...




                           Write as little of this as possible

Sunday, May 30, 2010
Pros
             • Small, reusable, readable, generic classes
             • Only the variables are managed in a specific application
             • The footprint between a specific app and your generic
                  codebase is as small as possible - only instantiation calls




Sunday, May 30, 2010
Pros
             • Small, reusable, readable, generic classes
             • Only the variables are managed in a specific application
             • The footprint between a specific app and your generic
                  codebase is as small as possible - only instantiation calls



                                      & Cons
             • Requires a bit more skill.
             • Can often mean more bytes of code in the short term.
             • Test driven development is a must.


Sunday, May 30, 2010
MooTools and Dojo Help You Do This




Sunday, May 30, 2010
MooTools and Dojo Help You Do This
                • MooTools and Dojo make JavaScript easier
                       (as do all toolkits & frameworks).




Sunday, May 30, 2010
MooTools and Dojo Help You Do This
                • MooTools and Dojo make JavaScript easier
                       (as do all toolkits & frameworks).

                • They encourage you to reuse your work,
                       and to write your code to be flexible for
                       future use.




Sunday, May 30, 2010
MooTools and Dojo Help You Do This
                • MooTools and Dojo make JavaScript easier
                       (as do all toolkits & frameworks).

                • They encourage you to reuse your work,
                       and to write your code to be flexible for
                       future use.

                • They are designed to be extended.




Sunday, May 30, 2010
MooTools and Dojo Help You Do This
                • MooTools and Dojo make JavaScript easier
                       (as do all toolkits & frameworks).

                • They encourage you to reuse your work,
                       and to write your code to be flexible for
                       future use.

                • They are designed to be extended.
                • These are qualities of JavaScript really;
                       MooTools and Dojo just make the interface
                       more accessible.


Sunday, May 30, 2010
Q&A
                       • http://bit.ly/dofyM5
                       • http://dojotoolkit.org/
                       • http://mootools.net/
                       • http://sitepen.com/
                       • http://jsfiddle.net/
                       • @dylans @dojo @mootools
                       • Thanks to Aaron Newton
Sunday, May 30, 2010

SWDC 2010: Programming to Patterns

  • 1.
    Programming To Patterns Dylan Schiemann (SitePen and Dojo) SWDC, June 2, 2010 Sunday, May 30, 2010
  • 2.
    Patterns? • Abstraction is the key • Focus less on the implementation at hand and more on the code • Think in terms of an API • Imagine using it somewhere else • Write granular, atomic components • Use Test Driven Development Sunday, May 30, 2010
  • 3.
    Example 1: The Namespaced Library Sunday, May 30, 2010
  • 4.
    Example 1: The Namespaced Library Classes DatePicker FormValidator Fx Request Slideshow etc... Sunday, May 30, 2010
  • 5.
    Example 1: The Namespaced Library var myApp = { init: function(){ myApp.apples() myApp.orange() Classes myApp.lemons() DatePicker }, FormValidator apples: function(){ Fx $$(‘div.apple’).each(function(apple) { Request var form = apple.getElement(‘form’); Slideshow form.addEvent(‘submit’, function(event){ ....}); etc... }); }, orange: function(){ $(‘orange’).getElements(‘li’).each... }, etc... Sunday, May 30, 2010
  • 6.
    Example 1: The Namespaced Library var myApp = { init: function(){ myApp.apples() myApp.orange() Classes myApp.lemons() DatePicker }, FormValidator apples: function(){ Fx $$(‘div.apple’).each(function(apple) { Request var form = apple.getElement(‘form’); Slideshow form.addEvent(‘submit’, function(event){ ....}); etc... }); }, orange: function(){ $(‘orange’).getElements(‘li’).each... }, etc... This tends to get out of hand Sunday, May 30, 2010
  • 7.
    Banging it out... <script>dojo.ready(function() { dojo.connect(dojo.byId('myForm'), 'onsubmit', function(evt){ dojo.stopEvent(evt); var formNode = evt.target; dojo.xhrPost({ form: formNode, url: formNode.action, handle: function(response, ioArgs){                 dojo.byId('myContainer').innerHTML = response;             }  });});}); </script> This is very tempting. Sunday, May 30, 2010
  • 8.
    Pros • Writing the logic for a specific app is fast and furious • The test environment is the app Sunday, May 30, 2010
  • 9.
    Pros • Writing the logic for a specific app is fast and furious • The test environment is the app & Cons • It’s much harder to maintain • A high percentage of code you write for the app isn’t reusable • The test environment is the app Sunday, May 30, 2010
  • 10.
    What to do? • Objects; stateful objects • Some people think of these as “Classes” • This is how JavaScript itself solves these problems • Most toolkits/frameworks help you do this Sunday, May 30, 2010
  • 11.
  • 12.
    ` This is how MooTools does it var Human = new Class({ isAlive: true, energy: 1, eat: function(){ this.energy++; } }); Human Sunday, May 30, 2010
  • 13.
    ` This is how MooTools does it var Human = new Class({ isAlive: true, energy: 1, eat: function(){ this.energy++; } }); var bob = new Human(); //bob.energy === 1 bob.eat(); //bob.energy === 2 Human bob Sunday, May 30, 2010
  • 14.
    ` This is how This is how MooTools does it Dojo does it var Human = new Class({ dojo.declare("Human", isAlive: true, null, { energy: 1, isAlive: true, eat: function(){ energy: 1, this.energy++; eat: function(){ } this.energy++; }); } } ); var bob = new Human(); //bob.energy === 1 var bob = new Human(); bob.eat(); //bob.energy === 1 //bob.energy === 2 bob.eat(); //bob.energy === 2 Sunday, May 30, 2010
  • 15.
  • 16.
    Prototypes var humanBase = { isAlive: true, energy: 1, eat: function(){ this.energy++; } }; humanBase object (our prototype) Sunday, May 30, 2010
  • 17.
    Prototypes var humanBase = { //MooTools isAlive: true, var Human = energy: 1, new Class(humanBase); eat: function(){ this.energy++; //Dojo } dojo.declare(“Human”, }; null, humanBase); humanBase Human object (our prototype) Function (constructor) Sunday, May 30, 2010
  • 18.
    Prototypes var humanBase = { //MooTools isAlive: true, var Human = energy: 1, new Class(humanBase); //MooTools & Dojo eat: function(){ var bob = new Human() this.energy++; //Dojo } dojo.declare(“Human”, }; null, humanBase); humanBase Human bob object (our prototype) Function (constructor) object (our instance) Sunday, May 30, 2010
  • 19.
    Prototypes energy == energy == 1 humanBase Human bob undefined object (our prototype) Function (constructor) object (our instance) bob.energy == Human.prototype.energy Sunday, May 30, 2010
  • 20.
    Prototypes energy == energy == 1 humanBase Human bob undefined object (our prototype) Function (constructor) object (our instance) bob.energy == Human.prototype.energy bob.foo == undefined //bob.foo AND Human.prototype.foo are not found Sunday, May 30, 2010
  • 21.
    Prototypes energy == energy == 1 humanBase Human bob undefined foo == “bar” object (our prototype) Function (constructor) object (our instance) bob.energy == Human.prototype.energy bob.foo == undefined //bob.foo AND Human.prototype.foo are not found bob.foo = “bar” //bob has a “foo” property, the prototype is not checked Sunday, May 30, 2010
  • 22.
    Prototypes energy == 1 energy == 2 humanBase Human bob foo == “bar” object (our prototype) Function (constructor) object (our instance) bob.energy == Human.prototype.energy bob.foo == undefined //bob.foo AND Human.prototype.foo are not found bob.foo = “bar” //bob has a “foo” property, the prototype is not checked bob.eat() //assigns a value to bob.energy; Human.prototype.energy is no //longer checked Sunday, May 30, 2010
  • 23.
    Extending Classes (MooTools) Sunday, May 30, 2010
  • 24.
    Extending Classes (MooTools) var Human = new Class({ initialize: function(name, age){ this.name = name; this.age = age; }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); Sunday, May 30, 2010
  • 25.
    Extending Classes (MooTools) var Human = new Class({ var Ninja = new Class({ initialize: function(name, age){ Extends: Human, this.name = name; initialize: function(side, name, age){ this.age = age; this.side = side; }, this.parent(name, age); isAlive: true, }, energy: 1, energy: 100, eat: function(){ attack: function(target){ this.energy++; this.energy = this.energy - 5; } target.isAlive = false; }); } }); Sunday, May 30, 2010
  • 26.
    Extending Classes (MooTools) var Human = new Class({ var Ninja = new Class({ initialize: function(name, age){ Extends: Human, this.name = name; initialize: function(side, name, age){ this.age = age; this.side = side; }, this.parent(name, age); isAlive: true, }, energy: 1, energy: 100, eat: function(){ attack: function(target){ this.energy++; this.energy = this.energy - 5; } target.isAlive = false; }); } }); Sunday, May 30, 2010
  • 27.
    Extending Classes (MooTools) var Human = new Class({ var Ninja = new Class({ initialize: function(name, age){ Extends: Human, this.name = name; initialize: function(side, name, age){ this.age = age; this.side = side; }, this.parent(name, age); isAlive: true, }, energy: 1, energy: 100, eat: function(){ attack: function(target){ this.energy++; this.energy = this.energy - 5; } target.isAlive = false; }); } }); var bob = new Human('Bob', 25); Sunday, May 30, 2010
  • 28.
    Extending Classes (MooTools) var Human = new Class({ var Ninja = new Class({ initialize: function(name, age){ Extends: Human, this.name = name; initialize: function(side, name, age){ this.age = age; this.side = side; }, this.parent(name, age); isAlive: true, }, energy: 1, energy: 100, eat: function(){ attack: function(target){ this.energy++; this.energy = this.energy - 5; } target.isAlive = false; }); } }); var bob = new Human('Bob', 25); var blackNinja = new Ninja('evil', 'Nin Tendo', 'unknown'); //blackNinja.isAlive = true //blackNinja.name = 'Nin Tendo' blackNinja.attack(bob); //bob never had a chance Sunday, May 30, 2010
  • 29.
    Extending Classes (Dojo) Sunday, May 30, 2010
  • 30.
    Extending Classes (Dojo) dojo.declare("Human", null, { constructor: function(kwArgs) { dojo.mixin(this, kwArgs); }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); Sunday, May 30, 2010
  • 31.
    Extending Classes (Dojo) dojo.declare("Human", null, { dojo.declare(“Ninja”, Human, constructor: function(kwArgs) { { dojo.mixin(this, kwArgs); // Auto constructor inheritance }, energy: 100, isAlive: true, attack: function(target){ energy: 1, this.energy = this.energy - 5; eat: function(){ target.isAlive = false; this.energy++; } } ); }); Sunday, May 30, 2010
  • 32.
    Extending Classes (Dojo) dojo.declare("Human", null, { dojo.declare(“Ninja”, Human, constructor: function(kwArgs) { { dojo.mixin(this, kwArgs); // Auto constructor inheritance }, energy: 100, isAlive: true, attack: function(target){ energy: 1, this.energy = this.energy - 5; eat: function(){ target.isAlive = false; this.energy++; } } ); }); Sunday, May 30, 2010
  • 33.
    Extending Classes (Dojo) dojo.declare("Human", null, { dojo.declare(“Ninja”, Human, constructor: function(kwArgs) { { dojo.mixin(this, kwArgs); // Auto constructor inheritance }, energy: 100, isAlive: true, attack: function(target){ energy: 1, this.energy = this.energy - 5; eat: function(){ target.isAlive = false; this.energy++; } } ); }); var bob = new Human({name:'Bob', age: 25}); Sunday, May 30, 2010
  • 34.
    Extending Classes (Dojo) dojo.declare("Human", null, { dojo.declare(“Ninja”, Human, constructor: function(kwArgs) { { dojo.mixin(this, kwArgs); // Auto constructor inheritance }, energy: 100, isAlive: true, attack: function(target){ energy: 1, this.energy = this.energy - 5; eat: function(){ target.isAlive = false; this.energy++; } } ); }); var bob = new Human({name:'Bob', age: 25}); var blackNinja = new Ninja({side:'evil', name:'Nin Tendo', age:'unknown'}); //blackNinja.isAlive = true //blackNinja.name = 'Nin Tendo' blackNinja.attack(bob); //bob never had a chance Sunday, May 30, 2010
  • 35.
  • 36.
    Mixins with Dojo dojo.declare(“Human”, null, { constructor: function(kwArgs) { dojo.mixin(this, kwArgs); }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); Sunday, May 30, 2010
  • 37.
    Mixins with Dojo dojo.declare(“Human”, null, { constructor: function(kwArgs) { dojo.mixin(this, kwArgs); }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); dojo.declare(“Warrior”, null, { energy: 100, kills: 0, attack: function(target){ if (target.energy < this.energy) { target.isAlive = false; this.kills++; } this.energy = this.energy - 5; } }); Sunday, May 30, 2010
  • 38.
    Mixins with Dojo dojo.declare(“Human”, null, { dojo.declare(“Ninja”, [Human, Warrior], { constructor: function(kwArgs) { }); dojo.mixin(this, kwArgs); }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); dojo.declare(“Samurai”, [Human, Warrior], { side: 'good', dojo.declare(“Warrior”, null, { energy: 1000 energy: 100, }); kills: 0, attack: function(target){ if (target.energy < this.energy) { target.isAlive = false; this.kills++; } this.energy = this.energy - 5; } }); Sunday, May 30, 2010
  • 39.
  • 40.
    Mixins with MooTools var Human = new Class({ initialize: function(name, age){ this.name = name; this.age = age; }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); Sunday, May 30, 2010
  • 41.
    Mixins with MooTools var Human = new Class({ initialize: function(name, age){ this.name = name; this.age = age; }, isAlive: true, energy: 1, eat: function(){ this.energy++; } }); var Warrior = new Class({ energy: 100, kills: 0, attack: function(target){ if (target.energy < this.energy) { target.isAlive = false; this.kills++; } this.energy = this.energy - 5; } }); Sunday, May 30, 2010
  • 42.
    Mixins with MooTools var Human = new Class({ var Ninja = new Class({ initialize: function(name, age){ Extends: Human, this.name = name; Implements: [Warrior], this.age = age; initialize: function(side, name, age){ }, this.side = side; isAlive: true, this.parent(name, age); energy: 1, } eat: function(){ }); this.energy++; } }); var Warrior = new Class({ var Samurai = new Class({ energy: 100, Extends: Human, kills: 0, Implements: [Warrior], attack: function(target){ side: 'good', if (target.energy < this.energy) { energy: 1000 target.isAlive = false; }); this.kills++; } this.energy = this.energy - 5; } }); Sunday, May 30, 2010
  • 43.
    When to writea class... Sunday, May 30, 2010
  • 44.
    When to writea class... Sunday, May 30, 2010
  • 45.
    When to writea class... Sunday, May 30, 2010
  • 46.
    When to writea class... Sunday, May 30, 2010
  • 47.
    When to writea class... Sunday, May 30, 2010
  • 48.
  • 49.
    Best Practices • Shallow inheritance works best. Sunday, May 30, 2010
  • 50.
    Best Practices • Shallow inheritance works best. • Break up logic into small methods. Sunday, May 30, 2010
  • 51.
    Best Practices • Shallow inheritance works best. • Break up logic into small methods. • Break up functionality into small classes. Sunday, May 30, 2010
  • 52.
    Best Practices • Shallow inheritance works best. • Break up logic into small methods. • Break up functionality into small classes. • Build ‘controller’ classes for grouped functionality. Sunday, May 30, 2010
  • 53.
    Best Practices • Shallow inheritance works best. • Break up logic into small methods. • Break up functionality into small classes. • Build ‘controller’ classes for grouped functionality. • Use options and events liberally. Sunday, May 30, 2010
  • 54.
    Best Practices • Shallow inheritance works best. • Break up logic into small methods. • Break up functionality into small classes. • Build ‘controller’ classes for grouped functionality. • Use options and events liberally. • Don’t be afraid to refactor, but avoid breaking the interface. Sunday, May 30, 2010
  • 55.
    Let’s look atthat earlier example again <script>dojo.ready(function() { dojo.connect(dojo.byId('myForm'), 'onsubmit',function(evt){ dojo.stopEvent(evt); var formNode = evt.target; dojo.xhrPost({ form: formNode, url: formNode.action, handle: function(response, ioArgs){       dojo.byId('myContainer').innerHTML = response; }  });});}); Sunday, May 30, 2010
  • 56.
    And here's theMooTools version <script>window.addEvent(‘domready’, function(){ $(‘myForm’).addEvent(‘submit’, function(evt){ evt.preventDefault(); this.set(‘send’, { onComplete: function(result){ $(‘myContainer’).set(‘html’, result); } }); this.send(); }); });</script> Sunday, May 30, 2010
  • 57.
    Program a Pattern var FormUpdater = new Class({ initialize: function(form, container, options) { this.form = $(form); this.container = $(container); this.request = new Request(options); this.request.addEvent(‘success’,this.onComplete.bind(this)); this.attach(); }, attach: function(){ this.form.addEvent(‘submit’,this.send.bind(this)); }, send: function(evt){ if (evt) evt.preventDefault(); this.request.send({ url: this.form.get(‘action’), data: this.form }); }, onComplete: function(responseTxt){ this.container.set(‘html’, responseTxt); } }); new FormUpdater($(‘myForm’), $(‘myContainer’)); Sunday, May 30, 2010
  • 58.
    ...and the DojoVersion dojo.declare(‘foo.FormUpdater’, null, { constructor: function(form, container, options) { this.form = form; this.container = container; this.requestOptions = options; this.attach(); }, attach: function(){ dojo.connect(this.form, ‘onsubmit’, this ‘send’); }, send: function(evt){ if(evt) dojo.stopEvent(evt); dojo.xhrPost(dojo.mixin({ form: this.form, url: this.form.action, handle: dojo.hitch(this, "onComplete") }, this.requestOptions)); }, onComplete: function(data){ dojo.attr(this.container, ‘innerHTML’, data); } }); new foo.FormUpdater(dojo.byId(‘myForm’), dojo.byId(‘myContainer’)); Sunday, May 30, 2010
  • 59.
    And then extendit... dojo.declare(“foo.FormUpdater.Append”, FormUpdater, { onComplete: function(data){ dojo.create(‘p’, {innerHTML: data}, this.container); } }); new foo.FormUpdater.Append(dojo.byId(‘myForm’), dojo.byId(‘myTarget’)); Sunday, May 30, 2010
  • 60.
    The MooTools version... var FormUpdater.Append = new Class({ Extends: FormUpdater, onComplete: function(responseTxt){ this.container.adopt( new Element(‘div’, {html: responseTxt}) ); } }); new FormUpdater.Append($(‘myForm’), $(‘myTarget’)); Sunday, May 30, 2010
  • 61.
  • 62.
    Developing with Class var myApp = { init: function(){ myApp.apples() Classes myApp.orange() DatePicker myApp.lemons() FormValidator }, Fx apples: function(){ Request new AppleGroup($$(‘div.apple’)); Slideshow }, Apple orange: function(){ AppleGroup new Orange($(‘orange’) Orange }, etc... etc... Sunday, May 30, 2010
  • 63.
    Developing with Class var myApp = { init: function(){ myApp.apples() Classes myApp.orange() DatePicker myApp.lemons() FormValidator }, Fx apples: function(){ Request new AppleGroup($$(‘div.apple’)); Slideshow }, Apple orange: function(){ AppleGroup new Orange($(‘orange’) Orange }, etc... etc... Write as little of this as possible Sunday, May 30, 2010
  • 64.
    Pros • Small, reusable, readable, generic classes • Only the variables are managed in a specific application • The footprint between a specific app and your generic codebase is as small as possible - only instantiation calls Sunday, May 30, 2010
  • 65.
    Pros • Small, reusable, readable, generic classes • Only the variables are managed in a specific application • The footprint between a specific app and your generic codebase is as small as possible - only instantiation calls & Cons • Requires a bit more skill. • Can often mean more bytes of code in the short term. • Test driven development is a must. Sunday, May 30, 2010
  • 66.
    MooTools and DojoHelp You Do This Sunday, May 30, 2010
  • 67.
    MooTools and DojoHelp You Do This • MooTools and Dojo make JavaScript easier (as do all toolkits & frameworks). Sunday, May 30, 2010
  • 68.
    MooTools and DojoHelp You Do This • MooTools and Dojo make JavaScript easier (as do all toolkits & frameworks). • They encourage you to reuse your work, and to write your code to be flexible for future use. Sunday, May 30, 2010
  • 69.
    MooTools and DojoHelp You Do This • MooTools and Dojo make JavaScript easier (as do all toolkits & frameworks). • They encourage you to reuse your work, and to write your code to be flexible for future use. • They are designed to be extended. Sunday, May 30, 2010
  • 70.
    MooTools and DojoHelp You Do This • MooTools and Dojo make JavaScript easier (as do all toolkits & frameworks). • They encourage you to reuse your work, and to write your code to be flexible for future use. • They are designed to be extended. • These are qualities of JavaScript really; MooTools and Dojo just make the interface more accessible. Sunday, May 30, 2010
  • 71.
    Q&A • http://bit.ly/dofyM5 • http://dojotoolkit.org/ • http://mootools.net/ • http://sitepen.com/ • http://jsfiddle.net/ • @dylans @dojo @mootools • Thanks to Aaron Newton Sunday, May 30, 2010