Successfully reported this slideshow.
Your SlideShare is downloading. ×

Maintainable JavaScript 2011

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 53 Ad

Maintainable JavaScript 2011

Download to read offline

Writing JavaScript as a hobby and writing JavaScript as a job are two very different things. Learn some common practices for making your JavaScript friendly to a team environment.

Writing JavaScript as a hobby and writing JavaScript as a job are two very different things. Learn some common practices for making your JavaScript friendly to a team environment.

Advertisement
Advertisement

More Related Content

Viewers also liked (20)

Advertisement

Similar to Maintainable JavaScript 2011 (20)

More from Nicholas Zakas (20)

Advertisement

Recently uploaded (20)

Maintainable JavaScript 2011

  1. 1. flickr.com/photos/jontysewell/4526861658/ Maintainable JavaScript Nicholas C. Zakas | @slicknet
  2. 2. Who's this guy? 5 years Co-Creator Contributor, Tech Lead, Yahoo! csslint.net Creator of YUI Test Author Lead Author Contributor Lead Author
  3. 3. Maintainability Why do we care?
  4. 4. flickr.com/photos/indraw/4857101224/ Most of your time is spent maintaining code
  5. 5. Who cares? Your Employer Your Co-workers, Present and Future
  6. 6. flickr.com/photos/protestphotos1/4726566233/ We all want to be rock stars "Don't mess with my process, man! It's about the music!"
  7. 7. flickr.com/photos/the_junes/3120810156/ At work, you're part of a team Awesome happens when everyone is on the same page
  8. 8. Maintainable code is Understandable Adaptable Debuggable Testable Intuitive Extendable
  9. 9. Code Conventions Understandable Intuitive
  10. 10. flickr.com/photos/29271559@N02/5799773313/ "Programs are meant to be read by humans and only incidentally for computers to execute." Donald Knuth
  11. 11. flickr.com/photos/polinasergeeva/3052378826/ Tabs for indentation 4 spaces for indentation Indentation
  12. 12. 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]; } } } }
  13. 13. 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]; } } } }
  14. 14. flickr.com/photos/polinasergeeva/3052378826/ Comments
  15. 15. /** * 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
  16. 16. 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
  17. 17. while (element &&(element = element[axis])){ //NOTE: assignment if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { return element; } } Code that might seem to be wrong
  18. 18. Naming flickr.com/photos/kaatje/243834320/
  19. 19. Naming • Use logical names for variables and functions – Don't 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", such as isValid() • Avoid useless names such as foo and temp
  20. 20. 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]; } } } }
  21. 21. Loose Coupling Adaptable Debuggable Extendable
  22. 22. Front End Layers Presentation Behavior (CSS) (JavaScript) Base JS Data/Structure (HTML)
  23. 23. Don't cross the streams
  24. 24. <button onclick="doSomething()">Click Me</button> Keep JavaScript out of HTML
  25. 25. var element = document.getElementById("container"); element.innerHTML = "<div class="popup"></div>"; Keep HTML out of JavaScript
  26. 26. .foo { width: expression(document.offsetWidth + "px"); } Keep JavaScript out of CSS
  27. 27. var element = document.getElementById("container"); element.style.color = "red"; element.style.cssText = "background:blue;border:1px solid red"; Keep CSS out of JavaScript
  28. 28. Programming Practices Adaptable Debuggable Testable Extendable
  29. 29. //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
  30. 30. //better, but still wrong function 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"; } Don't pass the event object around
  31. 31. //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
  32. 32. //don't add new methods Array.prototype.awYeah = function(){ alert("Aw yeah!"); }; //don't override methods YUI.use = function(){ alert("Aw yeah!"); }; Don't modify objects you don't own If you didn't define the object yourself, you don't own it
  33. 33. nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/
  34. 34. 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
  35. 35. 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
  36. 36. var Controller = { addClass: function(element, className){ element.className += " " + className; } }; Throw your own errors When you know a function will fail
  37. 37. 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
  38. 38. var Controller = { process: function(items){ if (items != null){ items.sort(); items.forEach(function(item){ //do something }); } } }; Avoid null comparisons
  39. 39. 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
  40. 40. 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"
  41. 41. function validate(value) { if (!value) { alert("Invalid value"); location.href = "/errors/invalid.php"; } } Separate config data
  42. 42. 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
  43. 43. 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
  44. 44. Build Process Understandable Testable
  45. 45. Build Process Build
  46. 46. Build Add/Remove Validate Debugging Code Concatenate Minify Files Files Generate Deploy Documentation Files
  47. 47. Build Development Testing Deployment
  48. 48. Recommendations • One object or object definition per file – Track dependencies • Use a build process to combines files – Determines correct order – Validates code (JSHint) – Minifies code (YUI Compressor) – Generate documentation (YUI Doc)
  49. 49. http://www.julienlecomte.net/blog/2007/09/16/
  50. 50. Recap
  51. 51. Remember • Code conventions ensure everyone's speaking the same language • Loose coupling of layers make changes and debugging easier • Good programming practices allow you to • Code organization and a build process help to bring sanity to an otherwise crazy process
  52. 52. Questions?
  53. 53. Etcetera • My blog: www.nczonline.net • Twitter: @slicknet • These Slides: slideshare.net/nzakas

×