SWDC 2010: Programming to Patterns

  • 1,071 views
Uploaded on

Slides from SWDC conference on June 2, 2010. Talk compares simple approaches to patterns using Dojo and MooTools.

Slides from SWDC conference on June 2, 2010. Talk compares simple approaches to patterns using Dojo and MooTools.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
1,071
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
0
Comments
1
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 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. ` Sunday, May 30, 2010
  • 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. Prototypes Sunday, May 30, 2010
  • 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. Mixins with Dojo Sunday, May 30, 2010
  • 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. Mixins with MooTools Sunday, May 30, 2010
  • 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 write a class... Sunday, May 30, 2010
  • 44. When to write a class... Sunday, May 30, 2010
  • 45. When to write a class... Sunday, May 30, 2010
  • 46. When to write a class... Sunday, May 30, 2010
  • 47. When to write a class... Sunday, May 30, 2010
  • 48. Best Practices Sunday, May 30, 2010
  • 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 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
  • 56. 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
  • 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 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
  • 59. 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
  • 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. Developing with Class Sunday, May 30, 2010
  • 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 Dojo Help You Do This Sunday, May 30, 2010
  • 67. MooTools and Dojo Help You Do This • MooTools and Dojo make JavaScript easier (as do all toolkits & frameworks). Sunday, May 30, 2010
  • 68. 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
  • 69. 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
  • 70. 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
  • 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