0
Hardcore                              JavaScript                              Write it Right      By     Mike Wilcox      ...
Readable Code    here(will make that book very    |resistånt to pressure| to read.)    there(isn’t explained properly)    ...
What do I know??         me                                        s Cro ckford                              D o ug laWedn...
What do I know??    Brend                          me                        an Eic                               hWednesd...
What do I know??      Seriously…      Being a Dojo Committer means not only having      your code and style scrutinized by...
This code sucks!      onPlayerParams = function(dfd){      ! dfd = dfd || new this.Deferred();      ! var o, p;      ! if(...
Our Excuses                                We                                                     The                     ...
JavaScript                                    guide                                            StyleWednesday, February 6,...
Formatting    Formatting must be consistent. Otherwise little    distractions make the code noisy and that much harder    ...
Formatting    Use single quotes, use spaces liberally, don’t use tiny,    cryptic variable names and declare all variables...
Typical Guides                Indentation tabs not spaces                Spacing / whitespace                Curly braces ...
JSLint / JSHint                Is it automated into your build?                It’s not just a suggestion - listen to it! ...
CommentsWednesday, February 6, 2013
Comments                         Why the hell did I                                       write that??    OS comments vs p...
Levels of Documenting          1. Verbose comments on every method and module,             README and Wiki, instructions f...
The Myth    You think your code is self documenting, huh? This is not    self documenting:      setCommand = function(c){ ...
The Myth    What your self documenting code would look like:       setListItemsWithDescritionsButNoThumbnails = function( ...
Don’t be that guy                                                     When a dev writes crap    Comment quality matters   ...
PropertiesWednesday, February 6, 2013
Naming Conventions                Should be camel case                Upper case                Whole names, no abbreviati...
Property Bags                Multiple arguments (more than 3) are difficult to                manage                       ...
ARG-uments      function Widget(node, name, description, color, size){         this.node = node;         this.name = name ...
Property Bag Example      function Widget( options ){         util.mixin( this, options ); // Done!      }    Even better ...
getters & setters    Initialization      var object = {      ! _x: 7,      ! get x() { return this.x + 1; },      ! set x(...
ES3 getters & setters    Initialization      var object = {      ! x: 7,      ! get: function( key ) { return this[ key ];...
Observers & Watchers      object.watch( x, function( value ){      ! moveObject( x );      });      object.observe( x, fun...
Binding      <div class=Widget>      ! <span data-bind=name></name>      </div>      Widget = declare({      ! name:Untitl...
Functions and MethodsWednesday, February 6, 2013
Naming Conventions                Camel case                Pascal case for constructors (Classes)                Should b...
Ambivalence      function                process(){}      function                state(){}      function                c...
Side Effects   While side effects are not forbidden, you should   still consider the consequences     function setImagePro...
Monolithic Functions                                                                     1970 called and wants their      ...
Repetition   This ain’t Java. You shouldn’t have code like this.     function setListeners(){     ! this.domNode.addEventL...
Repetition   JavaScript is a dynamic language and can   handle repetition in multiple ways.     [onmousedown, onmouseup, o...
Function in Functions   Functions inside of other functions are perfectly   legitimate, but still should be used with care...
Function in Functions                Often slower, as each time the outer is invoked, the                inners are recrea...
Loops                Where the biggest performance boost (or hit) can                happen                Hot Loops      ...
Loops - for vs forEach                for is much faster, used in context and can be easily                interrupted wit...
Functions in Loops     for( var i = 0; i < arguments.length; i++){     ! var handler = (function(node){     ! ! return nod...
for vs for-in           for-in is for objects, for is for arrays.   If I see you do this                                  ...
ObjectsWednesday, February 6, 2013
Don’t fight “this”                                                             meth                  var instance = {      ...
Don’t fight “this”    You *could* bind the submethod to the parent object...      var instance = {      ! doit: function(){...
Don’t cross the beams!!    One solution...      var instance = {      ! constructor: function(){      ! ! aop.after(this.s...
Know thy self    self is the common variable name used to pass around    and change context (this)      var self = this;  ...
Alternative to self    Context binding basically uses call or apply under the    hood      var bind = function(ctx, func){...
ES5 bind()    All modern browsers have Function.bind which can    change context      var instance = {      ! id:binder,  ...
Hate thy self too much    self is like chocolate cake - some is good, too much will    make you sick      var self = this;...
Love thy self a little    On solution is to immediately redirect to a properly bound    method      var instance = {      ...
Don’t abuse your self                this is specific; it can’t be changed so you always                know to which objec...
InheritanceWednesday, February 6, 2013
Prototypal Inheritance    If you are using the prototype keyword… you’re doing it    wrong.                               ...
dcl    A JavaScript package that implements OOP with mixins and    AOP at both “class” and object level.      var Base = d...
dcl / Inheritance                Base classes can be reused, keeping code light -                extremely important in Ja...
Other Design PatternsWednesday, February 6, 2013
Design Patterns Design Patterns: Elements of Reusable Object-Oriented Software is a book with solutions to common problems...
Over-Inherited    One reason for other solutions is to protect from over-    inheritance                                  ...
Declarative    A problem faced by libraries is allowing the dev to choose    discrete segments of code instead of kitchen ...
Decorator      define([      ], function( declare, Memory, Cache, JsonRest, Observable ){      !      ! var Store = declar...
Composition    Composition often makes sense semantically. Here the model    encapsulates properties and functionality.   ...
Functional                                      HMO                                                    Hot Mike Opinion   ...
App StructureWednesday, February 6, 2013
require.js                You are using it, aren’t you?                Globals are SO 2011                Globals can clas...
Naming and Arranging              Dont expect to cram it all into preconceived model-              view-controller folders...
Module APIs    Modules can use private variables, but not to hide or protect    anybody - use them to help provide a clean...
WiringWednesday, February 6, 2013
Wiring Types                tight coupling (direct access)                AOP                events                pubsub ...
Tight Coupling    Pros:      The intent is quite clear      Requires no additional libraries of fancy code    Cons:      O...
AOP               Uses JavaScript’s dynamic, mutable language               Doesn’t overwrite method, so many connections ...
Events         The new hotness         Multiple connections can be made         Intent is clear - obvious they are events ...
pubsub    Pros:      Library code is very simple      Can access distant areas of app    Cons:      Not guaranteed - pub c...
callbacks  Pros: Old-school, simple way of connecting async; clear code path  Cons: Only one connection, no propagation, m...
promises / deferreds      define([Deferred], function(Deferred){      ! return function(){      ! ! var dfd = new Deferred...
promises / deferreds    Pros:      Async      A when() library can handle both async and sync      Trendy (everybody is do...
ConclusionWednesday, February 6, 2013
Refactor!             Little projects always become big projects             You will never have all the information up fr...
Make it small. People                Committee Refactor!            It                                                    ...
Wednesday, February 6, 2013
Upcoming SlideShare
Loading in...5
×

Hardcore JavaScript – Write it Right

2,224

Published on

How to write maintainable JavaScript for web applications: covering everything from syntax and style, to hot loop performance, to application structure.

Published in: Technology

Transcript of "Hardcore JavaScript – Write it Right"

  1. 1. Hardcore JavaScript Write it Right By Mike Wilcox February 2013Wednesday, February 6, 2013
  2. 2. Readable Code here(will make that book very |resistånt to pressure| to read.) there(isn’t explained properly) !bad Code is. like-a-book THATis badly formatted no indentation. incorrect punctuation misspelled words improper capitalizedation-ed. Or uneven. ?LINE HEIGHTS here() If “the” names of the char.acters start. Changing, you dunno. where they are. && you+re not sure – WHAT they... are do-ing because it there(), the book will bee pretty-difficult to [comprehend].Wednesday, February 6, 2013
  3. 3. What do I know?? me s Cro ckford D o ug laWednesday, February 6, 2013
  4. 4. What do I know?? Brend me an Eic hWednesday, February 6, 2013
  5. 5. What do I know?? Seriously… Being a Dojo Committer means not only having your code and style scrutinized by know-it-all prima donnas, open source experts, but your results also get used by thousands of hacks that expect magic developers who expect quality code.Wednesday, February 6, 2013
  6. 6. This code sucks! onPlayerParams = function(dfd){ ! dfd = dfd || new this.Deferred(); ! var o, p; ! if(scriptNode && scriptNode.getAttribute("config")){ ! ! p = this.fixParams(scriptNode.getAttribute("config")); ! ! p.swf = this.root + "player.swf"; ! }else if(this.embed()){ ! ! var parts = this.embed().getAttribute("src").split("?"); ! ! o = this.strToObj(parts[1]); ! ! o.swf = parts[0]; ! ! p = this.fixParams(o); ! }else if(!this.domReady){ ! ! this.ready(this, function(){ ! ! ! this.onPlayerParams(dfd); ! ! }, true); ! ! if(!p) return dfd; !} ! if(p && p.vast){b.vast.parser.getXml(p.vast);} ! return dfd; }Wednesday, February 6, 2013
  7. 7. Our Excuses We The can always go project manager back and fix it later needs this now *I* can read it No time for comments It My was like that sloppy code when I started. means job security!Wednesday, February 6, 2013
  8. 8. JavaScript guide StyleWednesday, February 6, 2013
  9. 9. Formatting Formatting must be consistent. Otherwise little distractions make the code noisy and that much harder to read. var foo=”bar”+‘beer’+”bob”; for(var i=0;i<arguments.length;i++){} if(a&&b&&c&&d)return a;Wednesday, February 6, 2013
  10. 10. Formatting Use single quotes, use spaces liberally, don’t use tiny, cryptic variable names and declare all variables at the beginning of the block. var foo = ‘bar’ + ‘beer’ + ‘bob’; var i; for( i = 0; i < arguments.length; i++ ){} var apples = true, bananas = true, coconuts = true; if( apples && bananas && coconuts ){ return true; }Wednesday, February 6, 2013
  11. 11. Typical Guides Indentation tabs not spaces Spacing / whitespace Curly braces rules variable naming conventions Don’t be afraid of white space. method naming conventions No Dojo Case: upper, lower, camel, Pascal neces sar y! Dojo Style Guide http://dojotoolkit.org/community/styleGuideWednesday, February 6, 2013
  12. 12. JSLint / JSHint Is it automated into your build? It’s not just a suggestion - listen to it! It’s more than to help you find errors Helps promote consistency between devs Prevents unintended consequences If the linter thinks your code is ambiguous, so will other devs Helps you target JIT compilers, resulting in faster codeWednesday, February 6, 2013
  13. 13. CommentsWednesday, February 6, 2013
  14. 14. Comments Why the hell did I write that?? OS comments vs production comments short descriptions Future save the lazy crap Self No comments is like a book without chapters or page numbers They aren’t just for your boss or your replacementWednesday, February 6, 2013
  15. 15. Levels of Documenting 1. Verbose comments on every method and module, README and Wiki, instructions for setup and usage, guides to the software and how to edit it 2.Comments on most methods and modules, README with instructions for setup and a guide to what modules do 3.Brief comments on most methods and modules, README with instructions for setup 4.Unfinished codeWednesday, February 6, 2013
  16. 16. The Myth You think your code is self documenting, huh? This is not self documenting: setCommand = function(c){ this.cmds.push(c); } run = function(){ … } This looks more like self documenting: setListItemsWithDescritionsButNoThumbnails = function( … ){ this.listItemDescriptions = listItemDescriptionsArgument; } renderItemsWhichIsCalledAfterEveryPageResize = function(){ … }Wednesday, February 6, 2013
  17. 17. The Myth What your self documenting code would look like: setListItemsWithDescritionsButNoThumbnails = function( … ){ if(!this.itemsSetBoolenPreventSecondAttempt){ this.itemsSetBoolenPreventSecondAttempt = true; this.listItemDescriptions = listItemDescriptionsArgument; this.renderItemsWhichIsCalledAfterEveryPageResize(); this.onAfterRenderFunctionalStubEvent(); } “Good clean code requires very consistent and good naming conventions that are concise, and which dont attempt to embody an extended purpose” https://www.ibm.com/developerworks/mydeveloperworks/blogs/StylishGeek/entry/ bloated_names_and_the_myth_of_self_documenting_code11?lang=enWednesday, February 6, 2013
  18. 18. Don’t be that guy When a dev writes crap Comment quality matters like this, I want to function setParams(params){ paint him with meat paste and drop him on a ! // sets params mound of fire ants } function setVideo(video){ ! // set video } function setParams(params){ ! // sets parameters based on config property ! // from script tag } function setVideo(videoPath){ ! // Sets the path for the video object }Wednesday, February 6, 2013
  19. 19. PropertiesWednesday, February 6, 2013
  20. 20. Naming Conventions Should be camel case Upper case Whole names, no abbreviations This isn’t your father’s code. We have minifiers and gzip now. Use names we understand! Exceptions for long or often used names: err for error, dfd for deferred, prop for property, app for application, etc. i, k, j, etc, okay for iteratorsWednesday, February 6, 2013
  21. 21. Property Bags Multiple arguments (more than 3) are difficult to manage An single argument as an object of options allows any or all properties to be passed without concern of method signature Mixins allow for simple setting Works with super constructorsWednesday, February 6, 2013
  22. 22. ARG-uments function Widget(node, name, description, color, size){ this.node = node; this.name = name || “Untitled”; this. description = description || “”; this.color = color || “#FF0000”; this.size = size || 100; this.code = “makes me sad”; } new Widget({});Wednesday, February 6, 2013
  23. 23. Property Bag Example function Widget( options ){ util.mixin( this, options ); // Done! } Even better is to set defaults and use a mixin that only overwrites and does not add undefined properties var Widget = declare{ name:‘Untitled’, description:’’, color:’#FF0000’, size:100, constructor: function( options ){ util.mixin(this, options); // Done! } }Wednesday, February 6, 2013
  24. 24. getters & setters Initialization var object = { ! _x: 7, ! get x() { return this.x + 1; }, ! set x( arg ) { this.x = arg / 2; } }; After creation object.__defineGetter__("b", function() { return this.a + 1; }); object.__defineSetter__("c", function(x) { this.a = x / 2; }); ES5 getters and setters are still not widely used due to IE8. There are also issues as far as how inheritance would work. The super keyword is still in proposal.Wednesday, February 6, 2013
  25. 25. ES3 getters & setters Initialization var object = { ! x: 7, ! get: function( key ) { return this[ key ]; }, ! set: function( key, value ) { this[ key ] = value; } }; This is a very common and standardized pattern, even used in Node.js (Mongoose). It works with most library inheritance patterns.Wednesday, February 6, 2013
  26. 26. Observers & Watchers object.watch( x, function( value ){ ! moveObject( x ); }); object.observe( x, function( value ){ ! moveObject( x ); }); watch() is only available on Gecko with warnings of performance penalties. observe() is still an ES6 proposal. Common solution is to simply connect to widget.set method with aspect.after.Wednesday, February 6, 2013
  27. 27. Binding <div class=Widget> ! <span data-bind=name></name> </div> Widget = declare({ ! name:Untitled, ! set: function( key, value ){ ! ! this[ key ] = value; ! ! if( this.bindings[ key ] ){ ! ! ! this.bindings[ key ].innerHTML = value; !! } !} }); new Widget({ name: Bob }); This common pattern is the key to all of these trendy MVC frameworks.Wednesday, February 6, 2013
  28. 28. Functions and MethodsWednesday, February 6, 2013
  29. 29. Naming Conventions Camel case Pascal case for constructors (Classes) Should be verbs getItems, setName, build, Widget, etcWednesday, February 6, 2013
  30. 30. Ambivalence function process(){} function state(){} function command(){} function structure(){} Those are not verbs. process could be to perform operations or a series of steps state could be to state your name, or the current application state It’s not obvious what any of these do and they should at least be commentedWednesday, February 6, 2013
  31. 31. Side Effects While side effects are not forbidden, you should still consider the consequences function setImageProperties(){ image.width = 320; image.height = 240; image.x = 100; image.y = 10; image.opacity = 0.9; updateImage(); killPuppy(); } Can you spot the side effect?Wednesday, February 6, 2013
  32. 32. Monolithic Functions 1970 called and wants their fixParams = function(o){ ! var _vid = o.videoId || o.vid || o.siteId || ""; ! if(/,/.test(_vid)){ ! ! ! ! o.media = []; o.mediaParam = vid= + _vid; GOSUB back. ! ! _vid.split(,).forEach(function(id){ ! ! ! o.media.push({videoId:id}); ! ! ! ! }); if(o.titles){ Requires extra cognition ! ! ! o.mediaParam += &titles= + o.titles; ! ! ! o.titles.split(,).forEach(function(title, i){ ! ! ! ! ! ! ! }); o.media[i].caption = unescape(title); Limits reusability ! ! ! delete o.titles; ! ! } ! ! ! ! delete o.videoId; delete o.vid; Even if it means more bytes, should be broken into smaller ! ! delete o.siteId; ! }else if(o.media){ ! ! o.mediaParam = media= + o.media; ! } ! var vid = o.videoId || o.vid || o.siteId || ""; functions ! var lid = o.locationId || o.lid; ! var cid = Number(o.clientId) || o.cid; ! if(lid === 1 || lid === "1" || !lid) lid = 0; ! for(var nm in this.params){ ! ! if(o[nm] === undefined) o[nm] = this.params[nm]; ! } ! if(!o.videoId && !o.siteId && !o.vid && o.media){ ! ! if(/siteId/.test(o.media)){ ! ! ! var pms = this.strToObj(unescape(o.media)); ! ! ! this.settings.siteId = pms.siteId; ! ! } ! } Actual Code! See the whole thing here!Wednesday, February 6, 2013
  33. 33. Repetition This ain’t Java. You shouldn’t have code like this. function setListeners(){ ! this.domNode.addEventListener(onmousedown, this.onMouseDown); ! this.domNode.addEventListener(onmouseup, this.onMouseUp); ! this.domNode.addEventListener(onmousemove, this.onMouseMove); ! this.domNode.addEventListener(onmouseover, this.onMouseOver); ! this.domNode.addEventListener(onmouseout, this.onMouseOut); ! this.domNode.addEventListener(onmouseenter, this.onMouseEnter); ! this.domNode.addEventListener(onmouseleave, this.onMouseLeave); }Wednesday, February 6, 2013
  34. 34. Repetition JavaScript is a dynamic language and can handle repetition in multiple ways. [onmousedown, onmouseup, onmouseover].forEach(function(event){ ! this.domNode.addEventListener(event, this[event]); }, this); $(this.domNode).on(onmousedown, onmouseup, onmouseover, function (event){ ! handleMouseClick(event);! });Wednesday, February 6, 2013
  35. 35. Function in Functions Functions inside of other functions are perfectly legitimate, but still should be used with care and consideration. function parseDom(node){ ! function parseText(){} ! function parseAttributes(){} ! function parseChildren(){} ! function getNodeType(){} ! getNodeType(node); ! parseText(node.innerHTML); ! parseAttributes(node.attributes); ! parseChildren(node.childNodes); }Wednesday, February 6, 2013
  36. 36. Function in Functions Often slower, as each time the outer is invoked, the inners are recreated They are private and not accessible by other methods If inners are not semantically tied very closely to the outer, the intention may be confusing The inners should never access anything outside of the outer - aka, the application Else what was the point?Wednesday, February 6, 2013
  37. 37. Loops Where the biggest performance boost (or hit) can happen Hot Loops JIT compilers make assumptions, especially on loops Not a good place for being tricky Sparse arrays Arrays with lots of “holes” will slow down the iteration Some libraries, like Lo-Dash handle these holes and speed performanceWednesday, February 6, 2013
  38. 38. Loops - for vs forEach for is much faster, used in context and can be easily interrupted with a break or continue’d for is a major chore to type - looks very “C” forEach has the overhead of the function, and is used out of context unless the this argument is added which is an addition performance hit forEach is much more finger friendly, and fine to use in low performance situations map, some, every, filter etc. have same issues and should be used on small arraysWednesday, February 6, 2013
  39. 39. Functions in Loops for( var i = 0; i < arguments.length; i++){ ! var handler = (function(node){ ! ! return node.addEventListener(click, blah); ! })( arguments[i] ); ! handlers.push( handlers ); } JSLint will complain. Listen to it! Creates a new function on every iteration. Slow. Fix this by moving the function outside of the loop and calling it. This allows for JIT prediction.Wednesday, February 6, 2013
  40. 40. for vs for-in for-in is for objects, for is for arrays. If I see you do this I will give you a paper cut in the NO EXCEPTIONS! corner of your mouth and feed you for( var key in array ){ lemons doSomething( array[key] ); } Could access unwanted properties Not a guarantee of order Intent is not clear In fact, it’s more of a WTFWednesday, February 6, 2013
  41. 41. ObjectsWednesday, February 6, 2013
  42. 42. Don’t fight “this” meth var instance = { od t! doit: function(){ console.log(DOIT!); }, c ! subobject:{ je b ! ! submethod: function(){ o b- calls su ! ! ! doit(); // FAIL! ! ! ! this.doit(); // FAIL! ! ! ! parent.doit(); // No such thing! metho d !! } !} }; instance.subobject.submethod(); This is a simplified version of a much larger problemWednesday, February 6, 2013
  43. 43. Don’t fight “this” You *could* bind the submethod to the parent object... var instance = { ! doit: function(){ console.log(DOIT!); }, ! subobject:{ ! ! submethod: function(){ ! ! ! this.doit(); // works !! } !} }; instance.subobject.submethod = bind(instance, instance.subobject.submethod); instance.subobject.submethod(); Of course, this begs the question of why you created subobject in the first place.Wednesday, February 6, 2013
  44. 44. Don’t cross the beams!! One solution... var instance = { ! constructor: function(){ ! ! aop.after(this.subobject, submethod, this.doit.bind(this)); ! }, ! doit: function(){ console.log(DOIT!); }, ! subobject:{ ! ! submethod: function(){} !} }; Understanding that communication only goes “down”, never “up” will go a long way toward clear code and simplified execution pathsWednesday, February 6, 2013
  45. 45. Know thy self self is the common variable name used to pass around and change context (this) var self = this; props.forEach(function(prop){ ! self[ prop.key ] = prop.value; }); Because JavaScript is a closure based language, self can actually be very efficient. Believe it or not, this is slower: props.forEach(function(prop){ ! this[ prop.key ] = prop.value; }, this); http://kriszyp.name/2012/09/14/closure-based-instance-binding/Wednesday, February 6, 2013
  46. 46. Alternative to self Context binding basically uses call or apply under the hood var bind = function(ctx, func){ ! return function(){ func.apply(ctx, arguments); }; }; var instance = { ! constructor: function(props){ ! ! var setProps = bind(this, this.setProps); ! ! props.forEach(setProps); ! }, ! setProps: function(p){ ! ! console.log(p); !} }; instance.constructor([{a:1}, {b:2}]);Wednesday, February 6, 2013
  47. 47. ES5 bind() All modern browsers have Function.bind which can change context var instance = { ! id:binder, ! constructor: function(props){ ! ! setTimeout(function(){ ! ! ! console.log(this.id);! ! ! }.bind(this), 1); !} }; instance.constructor(); Note that even though it’s built into the language, it’s not faster than self. It is for readability and convenience, not hot loops.Wednesday, February 6, 2013
  48. 48. Hate thy self too much self is like chocolate cake - some is good, too much will make you sick var self = this; var onLoad = function(data){ ! self.title = data.title; ! self.description = data.description; ! self.setClients( data.clients ); ! self.on(finished, function(){ ! ! self.render( self.items ); ! ! setTimeout( function(){ ! ! ! self.emit( afterrender );! ! ! }, 1); ! }); };Wednesday, February 6, 2013
  49. 49. Love thy self a little On solution is to immediately redirect to a properly bound method var instance = { ! onDataLoaded: function(data){ ! ! // now set stuff ! }, ! constructor: function(props){ ! ! var self = this; ! ! var onLoad = function(data){ ! ! ! self.onDataLoaded(data); ! ! }; !} };Wednesday, February 6, 2013
  50. 50. Don’t abuse your self this is specific; it can’t be changed so you always know to which object it points self is ambiguous; it can point to many objects from any object, which obfuscates your intent Don’t use self to shortcut better practicesWednesday, February 6, 2013
  51. 51. InheritanceWednesday, February 6, 2013
  52. 52. Prototypal Inheritance If you are using the prototype keyword… you’re doing it wrong. HMO Hot Mike Opinion Widget = function(props){ ! mixin(this, this.props); }; Widget.prototype = { ! render: function(){}, ! setItems: function(){} } Using prototype makes multiple inheritance difficult, and without some kind of AOP help, the super constructors won’t work.Wednesday, February 6, 2013
  53. 53. dcl A JavaScript package that implements OOP with mixins and AOP at both “class” and object level. var Base = dcl(null, { var Example1 = dcl([Base, Mixin1],{ ! declaredClass: Base, ! constructor: function(params){ ! constructor: function(params){ ! ! this.name = params.name; ! ! this.title = params.title; ! }, ! } ! render: function(){ }); ! ! this.prepareProps(); ! ! // call Widget.render var Widget = dcl(null, { ! ! this.inherited(); ! declaredClass: Widget, ! } ! constructor: function(params){ }); ! ! this.className = params ! }, /*********************************/ ! render: function(){ widget = new Example1({ ! ! this.setTemplate(); ! title:My Widget, ! } ! name:widget, }); ! className:Widget }); http://www.dcljs.org/about/Wednesday, February 6, 2013
  54. 54. dcl / Inheritance Base classes can be reused, keeping code light - extremely important in JavaScript Constructors are chained and called in all bases, which can’t be done in standard object creation, such as Object.create super methods can be called with inherited(), so all base classes can use similar method names, keeping code standardized and less complex For ES5 strict mode there is AOP inheritanceWednesday, February 6, 2013
  55. 55. Other Design PatternsWednesday, February 6, 2013
  56. 56. Design Patterns Design Patterns: Elements of Reusable Object-Oriented Software is a book with solutions to common problems in software design. The authors are often referred to as the Gang of Four. Functional (Imperative) Declarative Decorator Composition http://en.wikipedia.org/wiki/Design_PatternsWednesday, February 6, 2013
  57. 57. Over-Inherited One reason for other solutions is to protect from over- inheritance Based on more Base actual code from ! +! Item my Flash days! ! ! +! ServerItem ! ! ! +! ImageItem ! ! ! ! +! ImageListItem ! ! ! ! ! +! ImageListItemDescription ! ! ! ! ! ! +! ImageListItemDescriptionClickable ! ! ! ! ! ! ! +! ImageListItemDescriptionClickableDraggable Note however, JavaScript does not have the same inheritance restrictions as Java, C++, Flash, or othersWednesday, February 6, 2013
  58. 58. Declarative A problem faced by libraries is allowing the dev to choose discrete segments of code instead of kitchen sink solutions define([ ! dojo/declare, ! dojo/store/Memory, ! dojo/store/Cache, ! dojo/store/JsonRest, ! dojo/store/Observable ], function( declare, Memory, Cache, JsonRest, Observable ){! ! var Store = declare( Memory, Cache, JsonRest ); var store = new Store( webserviceUrl ); }); The dev can dynamically create their own constructor with the mixins providedWednesday, February 6, 2013
  59. 59. Decorator define([ ], function( declare, Memory, Cache, JsonRest, Observable ){ ! ! var Store = declare( Memory, Cache, JsonRest ); ! var store = new Store( webserviceUrl ); observableStore = Observable( store ); cacheableStore = Cache( observableStore ); }); Decorators are not very common, but they do solve a few problems like working with existing objects that you can’t change, or creating two objects from the same base with different functionality.Wednesday, February 6, 2013
  60. 60. Composition Composition often makes sense semantically. Here the model encapsulates properties and functionality. Widget = { ! constructor: function(model){ ! ! this.model = model;! ! }, ! get: function(key){ ! ! return this.model.get(key); !} }Wednesday, February 6, 2013
  61. 61. Functional HMO Hot Mike Opinion Don’t. Just don’t. Friends don’t let friends write functional.Wednesday, February 6, 2013
  62. 62. App StructureWednesday, February 6, 2013
  63. 63. require.js You are using it, aren’t you? Globals are SO 2011 Globals can clash with other code, and they do not garbage collect require.js provides a mini-framework, enforcing packages, namespaces, and modulesWednesday, February 6, 2013
  64. 64. Naming and Arranging Dont expect to cram it all into preconceived model- view-controller folders, its too limiting, and the app will grow out of it Remember, the code path flows down, not up, so the deeper modules should not have access to root modulesWednesday, February 6, 2013
  65. 65. Module APIs Modules can use private variables, but not to hide or protect anybody - use them to help provide a clean API. And if you are doing so - make it a clear intent! define([], function(){ ! var items = []; ! function setItem(item){ ! ! items.push(item); !} ! function getItem(idx){ ! ! return items[idx]; !} ! return { ! ! setItem:setItem, ! ! getItem:getItem ! }; });Wednesday, February 6, 2013
  66. 66. WiringWednesday, February 6, 2013
  67. 67. Wiring Types tight coupling (direct access) AOP events pubsub callbacks promisesWednesday, February 6, 2013
  68. 68. Tight Coupling Pros: The intent is quite clear Requires no additional libraries of fancy code Cons: Over-use between modules can create a hairball Can break encapsulation define([ ! ./foo, ! ../../views/widgets/utils/thinger ], function(foo, thinger){ ! foo.doStuff(); ! thinger.stopStuff(); }); require.js allows for clear paths to distant modules, but if you are connecting to something this “far” away, you should probably do some restructuringWednesday, February 6, 2013
  69. 69. AOP Uses JavaScript’s dynamic, mutable language Doesn’t overwrite method, so many connections can be made Make sure to create names to indicate they are event- methods define([ ! aop, ! ./items ], function(aop, items){ ! function onLoaded(data){ ! ! console.log(data); ! }! ! aop(items, onLoad, onLoaded); });Wednesday, February 6, 2013
  70. 70. Events The new hotness Multiple connections can be made Intent is clear - obvious they are events and what they do define([dcl, Events], function(dcl, Events){ ! return new dcl(Events, { ! ! onDataLoaded: function(data){ ! ! ! this.emit(dataloaded, data); !! } ! }); }); define([./dataLoader], function(dataLoader){ ! function onDataLoaded(data){ ! ! console.log(data); !} ! dataLoader.on(dataloaded, onDataLoaded); });Wednesday, February 6, 2013
  71. 71. pubsub Pros: Library code is very simple Can access distant areas of app Cons: Not guaranteed - pub can fire before sub is ready Can be hard to follow code paths between unrelated modules Over-use can lead to race conditions define([pubsub], function(pubsub){ ! pubsub.publish(/module/loaded, {success:true}); }); define([pubsub], function(pubsub){ ! pubsub.subscribe(/module/loaded, function(object){ ! ! console.log(load success:, object.success); ! }); });Wednesday, February 6, 2013
  72. 72. callbacks Pros: Old-school, simple way of connecting async; clear code path Cons: Only one connection, no propagation, multiple callback nesting can cause “callback hell” define([], function(){ ! return { ! ! loadData: function(callback){ ! ! ! xhr(/getdata, { ! ! ! ! load: function(data){ ! ! ! ! ! callback(data); ! ! ! ! }});}}; }); define([./instance], function(instance){ ! function onDataLoaded(data){ ! ! console.log(data); !} ! instance.loadData(onDataLoaded); });Wednesday, February 6, 2013
  73. 73. promises / deferreds define([Deferred], function(Deferred){ ! return function(){ ! ! var dfd = new Deferred(); ! ! xhr(/getdata, { ! ! ! load: function(data){ ! ! ! ! dfd.resolve(data); ! ! ! }! ! ! }); ! ! return dfd; !} }); define([./loader], function(loader){ ! loader().then(function(data){ ! ! console.log(data); ! }); });Wednesday, February 6, 2013
  74. 74. promises / deferreds Pros: Async A when() library can handle both async and sync Trendy (everybody is doing it!!) Multiple connections can be made Propagates, and can be stopped Cons: Libraries are somewhat complex Requires (a lot) more code than a callback Has a tendency to swallow errors unexpectedly Can dominate the stacktrace and make it hard to debug errorsWednesday, February 6, 2013
  75. 75. ConclusionWednesday, February 6, 2013
  76. 76. Refactor! Little projects always become big projects You will never have all the information up front Sales can turn your app into FrankensteinWednesday, February 6, 2013
  77. 77. Make it small. People Committee Refactor! It sure is tall. Can like small. you make it LOOK short? But make it big inside. Oh! And four doors. Small with lots of doors. My Don’t son says it would spend too much on be cool if you could the trim. camp in it. Don’t spend too much on the wheels.Wednesday, February 6, 2013
  78. 78. Wednesday, February 6, 2013
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×