Maintainable JavaScript 2012

download Maintainable JavaScript 2012

If you can't read please download the document

description

Writing code as an individual and writing code as part of the team are two very different things. Learn the tips and tricks for writing JavaScript code as part of the team so that your code will continue to work for years to come.

Transcript of Maintainable JavaScript 2012

  • flickr.com/photos/jontysewell/4526861658/ Maintainable JavaScript Nicholas C. Zakas | Chief Architect, WellFurnished
  • New
  • @slicknet
  • MaintainabilityWhy do we care?
  • http://flickr.com/photos/indraw/4857101224/ Most of your time is spent maintaining code
  • Maintainability Who cares?
  • http://www.flickr.com/photos/jbiljr/1935937825/
  • http://flickr.com/photos/protestphotos1/4726566233/ We all want to be rock stars "Dont mess with my process, man! Its about the music!"
  • http://flickr.com/photos/12832008@N04/3027812968/
  • MaintainabilityWhat is maintainable code?
  • Maintainable code works for five years without major changes Intuitive Understandable Adaptable Extendable Debuggable Testablehttp://flickr.com/photos/simax/3390895249/
  • Be kind to your futureself.Chris Eppstein,Creator of Compass
  • Code Conventions ProgrammingCode Style Practices
  • Code Style GuideCommunicating with each other through code
  • Programs are meant to beread by humans andonly incidentally forcomputers to execute.H. Abelson and G. Sussman,The Structure and Interpretationof Computer Programs
  • https://twitter.com/sh1mmer/status/21446028923
  • http://javascript.crockford.com/code.html
  • http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
  • http://docs.jquery.com/JQuery_Core_Style_Guidelines
  • http://dojotoolkit.org/community/styleGuide
  • https://github.com/rwldrn/idiomatic.js/
  • http://flickr.com/photos/polinasergeeva/3052378826/ Tabs for indentation 4 spaces for indentation
  • if (wl && wl.length) { for (i = 0, l = wl.length; i < l; ++i) { p = wl[i]; type = Y.Lang.type(r[p]); if (s.hasOwnProperty(p)) { if (merge && type == object) { Y.mix(r[p], s[p]);} else if (ov || !(p in r)) { r[p] = s[p]; } } } }
  • if (wl && wl.length) { for (i = 0, l = wl.length; i < l; ++i) { p = wl[i]; type = Y.Lang.type(r[p]); if (s.hasOwnProperty(p)) { if (merge && type == object) { Y.mix(r[p], s[p]); } else if (ov || !(p in r)) { r[p] = s[p]; } } }}
  • https://twitter.com/slicknet/status/169903570047614977
  • if (found) { doSomething(); doSomethingElse(); }else { doAThirdThing(); doAFourthThing(); }
  • if (found) { doSomething(); doSomethingElse();} else { doAThirdThing(); doAFourthThing();}
  • http://flickr.com/photos/polinasergeeva/3052378826/ Comments
  • https://twitter.com/slicknet/statuses/3559283285
  • /** * Returns a new object containing all of the properties of * all the supplied objects. The properties from later objects * will overwrite those in earlier objects. Passing in a * single object will create a shallow copy of it. For a deep * copy, use clone. * @method merge * @for YUI * @param arguments {Object*} the objects to merge. * @return {object} the new merged object. */Y.merge = function() { var a = arguments, o = {}, i, l = a.length; for (i = 0; i < l; i = i + 1) { Y.mix(o, a[i], true); } return o;}; Every method
  • if (mode) { switch (mode) { case 1: // proto to proto return Y.mix(r.prototype, s.prototype, ov, wl, 0, merge); case 2: // object to object and proto to proto Y.mix(r.prototype, s.prototype, ov, wl, 0, merge); break; // pass through case 3: // proto to static return Y.mix(r, s.prototype, ov, wl, 0, merge); case 4: // static to proto return Y.mix(r.prototype, s, ov, wl, 0, merge); default: // object to object is what happens below }} Difficult-to-understand code
  • while (element &&(element = element[axis])){ //NOTE: assignment if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { return element; }} Code that might seem to be wrong
  • Naminghttp://flickr.com/photos/kaatje/243834320/
  • Naming Use logical names for variables and functions Dont worry about length Variable names should be nouns Function names should begin with a verb (i.e. getName()) Functions return booleans should begin with "is" or "has", such as isValid() or hasItem() Avoid useless names such as foo and temp
  • if (wl && wl.length) { for (i = 0, l = wl.length; i < l; ++i) { p = wl[i]; type = Y.Lang.type(r[p]); if (s.hasOwnProperty(p)) { if (merge && type == object) { Y.mix(r[p], s[p]); } else if (ov || !(p in r)) { r[p] = s[p]; } } }}
  • // Variables, functions, properties methodsvar myName = "Nicholas";function sayName() { alert(myName);}var person = { name: "Nicholas", sayName: function() { alert(this.name); }}; Camel Casing
  • What about acronyms?
  • var element = document.getElementById("my-div");element.innerHTML = "Hello world!"; WTF?var xhr = new XMLHttpRequest(); No, seriously WTF? Camel Casing
  • // Constant-like variablesvar HOVER_CLASS = "mouse-over";// Constructorsfunction Person(name) { this.name = name;}var me = new Person("Nicholas"); Camel Casing- Exceptions
  • Programming PracticesSmall patterns for common problems
  • There are two ways ofconstructing a softwaredesign: One way is to make itso simple that there areobviously no deficiencies andthe other way is to make it socomplicated that there are noobvious deficiencies.C.A.R. Hoare,Quicksort Developer
  • Front End LayersPresentation Behavior (CSS) (JavaScript) Base JS Data/Structure (HTML)
  • Dont cross thestreams
  • Click Me Keep JavaScript out of HTML
  • var element = document.getElementById("container");element.innerHTML = ""; Keep HTML out of JavaScript
  • .foo { width: expression(document.offsetWidth + "px");} Keep JavaScript out of CSS
  • var element = document.getElementById("container");element.style.color = "red";element.style.cssText = "background:blue;border:1px solid red"; Keep CSS out of JavaScript
  • //the wrong way!!!function handleClick(event){ var popup = document.getElementById("popup"); popup.style.left = event.clientX + "px"; popup.style.top = event.clientY + "px"; popup.className = "reveal";} Event handlers should only handle events
  • //better, but still wrongfunction handleClick(event){ showPopup(event);}function showPopup(event){ var popup = document.getElementById("popup"); popup.style.left = event.clientX + "px"; popup.style.top = event.clientY + "px"; popup.className = "reveal";} Dont pass the event object around
  • //win!!function handleClick(event){ showPopup(event.clientX, event.clientY);}function showPopup(x, y){ var popup = document.getElementById("popup"); popup.style.left = x + "px"; popup.style.top = y + "px"; popup.className = "reveal";} Properly separated event handling
  • //dont add new methodsArray.prototype.awYeah = function(){ alert("Aw yeah!");};//dont override methodsYUI.use = function(){ alert("Aw yeah!");}; Dont modify objects you dont own If you didnt define the object yourself, you dont own it
  • http://nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/
  • function handleClick(event){ showPopup(event.clientX, event.clientY);}function showPopup(x, y){ var popup = document.getElementById("popup"); popup.style.left = x + "px"; popup.style.top = y + "px"; popup.className = "reveal";} Avoid global functions and variables
  • var Controller = { handleClick: function(event){ this.showPopup(event.clientX, event.clientY); }, showPopup: function (x, y){ var popup = document.getElementById("popup"); popup.style.left = x + "px"; popup.style.top = y + "px"; popup.className = "reveal"; }}; Avoid global functions and variables Create a single global (if necessary) and attach everything to it
  • var Controller = { addClass: function(element, className){ element.className += " " + className; }}; Throw your own errors When you know a function will fail
  • var Controller = { addClass: function(element, className){ if (!element) { throw new Error("addClass: 1st argument missing."); } element.className += " " + className; }}; Throw your own errors When you know a function will fail
  • var Controller = { process: function(items){ if (items != null){ items.sort(); items.forEach(function(item){ //do something }); } }}; Avoid null comparisons
  • var Controller = { process: function(items){ if (items instanceof Array){ items.sort(); items.forEach(function(item){ //do something }); } }}; Avoid null comparisons Test for precisely what you want to know if it matters
  • Avoid null comparisons Use instanceof to test for specific object types object instanceof MyType Use typeof to test for primitive types typeof value == "string" BEWARE: typeof null == "object"
  • function validate(value) { if (!value) { alert("Invalid value"); location.href = "/errors/invalid.php"; }} Separate config data
  • var config = { urls: { invalid: "/errors/invalid.php" }, strs: { invalidmsg: "Invalid value" }};function validate(value) { if (!value) { alert(config.strs.invalidmsg); location.href = config.urls.invalid; }} Separate config data
  • Separate Config Data All URLs needed by the JavaScript Any strings that are displayed to the user Any HTML that needs to be created from JavaScript Settings (i.e., items per page) Repeated unique values Any value that may change in the future
  • https://github.com/nzakas/props2js
  • AutomationMake everyones life easier
  • Build Process Build
  • Build Add/Remove Validate Debugging Code Concatenate Test Code Files Generate Minify FilesDocumentation Deploy Files
  • Add/Remove Debugginghttps://github.com/moxiecode/js-build-tools
  • Generate Documentationhttp://usejsdoc.org
  • Generate Documentationhttp://yuilibrary.com/projects/yuidoc/
  • Generate Documentationhttp://jashkenas.github.com/docco/
  • Validate Codehttp://jslint.com
  • Validate Codehttp://jshint.com
  • Minify Fileshttp://yuilibrary.com/projects/yuicompressor/
  • Minify Fileshttps://github.com/mishoo/UglifyJS/
  • Minify Fileshttps://developers.google.com/closure/compiler/
  • Buildhttps://ant.apache.org
  • Buildhttp://www.julienlecomte.net/blog/2007/09/16/
  • Buildhttps://github.com/cowboy/grunt
  • Buildhttp://weblog.bocoup.com/introducing-grunt/
  • BuildDevelopment Testing Deployment Add/Remove Add/Remove Add/Remove Debugging Debugging Debugging Validate Validate Validate Code Code Code Test Code Test Code Test Code Generate Concatenate ConcatenateDocumentation Files Files Minify Files Minify Files Deploy Files
  • Recap
  • Remember Code style guidelines ensure everyones speaking the same language Loose coupling of layers make changes and debugging easier Good programming practices allow for easier debugging Code organization and automation help to bring sanity to an otherwise crazy process
  • https://twitter.com/kylerichter/status/15101151292694529
  • EtceteraMy company: wellfurnished.comMy blog: nczonline.netTwitter: @slicknetThese Slides: slideshare.net/nzakas