alexkras.com

  • Home
  • Top Posts
  • Resume
  • Projects
  • YouTube
  • Boots to Bytes
  • About
  • Contact

Summary of Maintainable JavaScript Talk by Nicholas C. Zakas

June 28, 2014 by Alex Kras 16 Comments


Why do we care? Most of out time is spent maintaining code.

If you open an editor and:

  • It’s blank – you are writing new code.
  • Something already there – you are maintaining code.

Most of us learned JavaScript on our own and developed our own “best” practices

Maintainability = Developing as a Team

What is Maintainable code

Works for 5 years without having to rewrite

Maintainable code is:

  • Intuitive – You look at it and it kind of makes sense.
  • Understandable – If you look at something more complicated for a while, you can understand what it does.
  • Adoptable – You want other people to be able to come in and make changes without feeling that the code is going to explode.
  • Extendable – You can build on top of the existing code to do more things.
  • Debug-able – Set up your code so somebody can step through it and figure out what it does.
  • Testable – If you can write unit and functional tests, it will save you a lot of time.

Be Kind to Your Future Self!
Chris Eppstein, Creator of Compass

Code Style

Communicate with each other through the code – Programs are meant to be read by humans

Style guides

  • Popular Style Guides
    • Crockford
    • Google JavaScript Style Guide
    • jQuery Core Style Guide
    • idiomatic.js
  • Pick a style for the team and stick to it. (Don’t have everybody indent the code however they like etc.)
  • Minimize amount of code per line – much less likely to have a merge conflict.
//Bad
if(found) { doSomething(); doSomethingElse();}
else { doMore(); doEvenMore();}
  • Best to space things out.
//Good
if(found) { 
    doSomething(); 
    doSomethingElse();
} else { 
    doMore(); 
    doEvenMore();
}

Comments

  • You shouldn’t have to read through entire file to understand what the code is doing.
  • Not too many comments though, just like good seasoning in cooking – just the right amount.

At the very least:

  • Add JaveDoc style comments at the top of each function.
/**
 * A simple demo function that outputs some text
 *
 * @param {String} text The text that will be written to console
 */
function demoFunction(text) {
    alert(text);
}
  • For a difficult to understand code.
switch(mode) {
    case 1: //First Visit
        doSomething();
        break
    case 2: //Every other visit
        doSomethingElse():
        break;
    default:
        doNothing();
}
  • Code that might seem wrong at a first look
while(element && (element = element[index])) { //Note: testing assignment, do not edit
    doSomething();
}
  • Browser specific code (i.e. IE6 workaround)
  • Make sure to add a comment, otherwise a helpful colleague will fix it for you 🙂

Use logical names for your functions and variables

  • Don’t worry about length, you can compress it during build process.
  • Variable names should be nouns (i.e. var book).
  • Function names should begin with a verb (i.e. getName()).
  • Avoid names that have no meaning (i.e. var a; function foo()).
  • Use camel casing since camelCasingIsTheJavascriptWay.
  • For Constant-like variables use – UPPER_CASE_WITH_UNDERSCORE.

Programming Practices

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies.
C.A.R Hoare, Quick-sort Developer

Keep Front Layer Separate

  • CSS – Presentation
  • JavaScript – Behavior
  • HTML – Data/Structure

Rules of the road

  • It is not intuitive to look for html code in javascript file, or for javascript code in html file
  • Keep your JavaScript out of HTML
    • Avoid <button onclick="doSomething()">Click Me</button>
  • Keep your HTML out of JavaScript
    • Avoid element.innerHTML = "<div class=\"popup\"></div>"
  • Keep JavaScript out of CSS
  • Use Templates!!!

Event Handlers should only handle events

  • Bad Example
//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";
}
  • Better Example – factor out function so it can be passed around and tested
//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";
}
  • Even better, don’t pass event object. Extract data that you need and pass that on to the function.
//Good
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";
}

Do Not modify objects that you do not own

 
//i.e. We extended 
Number.prototype.toFoo = function() { return "bar" };
Number(1).toFoo(); //Returns "bar"

//2 months later, developers at Chrome decide to implement the same method as
Number.prototype.toFoo = function() { return "baz" };

//It may break your code. And even if you force it to work, you could have a new co-worker join your team
//who would expect Number(1).toFoo() to return "baz" and she will be very confused to see "bar" instead.
  • Modifying existing methods is bad
  • Adding new methods is also bad. You don’t know what will happen in the future, what methods might be added to the original object.

Throw your own errors when you know functions will fail

  • It’s like another note to self or other programmers, when things might be hard to figure out.
var Controller = {
    addClass: function (element, className){
        if(!element){
            throw new Error("addClass: 1st argument missing");
        }
        element.className += " " + className;
    }
}

Avoid null comparisons, unless null value is specifically assigned

  • Bad
function(items){
    if(items != null){
        items.sort();
    }
    //Will work with:
    //var items = true;
    //var items = 1;
    //var items = "blah";   
}
  • Better communicate your intention and prevent false positive with:
function(items){
    if(items instanceof Array){
        items.sort();
    }
}
  • Use:
    • instanceof to test for specific object types
      • object instanceof MyType
    • typeof to test for primitive types
      • typeof value == "string"
    • BEWARE typeof null == object

Separate config data

  • Bad – Need to factor out items that might change
function validate(value) {
    if(!value){
        alert("Invalid value");
        location.href = "/errrors/invalid.php";
    }
}
  • Keep items data away from your application logic.
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;
    }
}
  • When you change data, you shouldn’t have to re-run unit tests to make sure logic is still the same
  • Items to factor out
    • URLs
    • All String displayed to user
    • Any HTML that needs to be created from Javascript – use templates.
    • Settings (i.e. Number of items per page)
    • Unique values that are repeated multiple times

Automation (make everybody’s life easier)

Build process is magic

  • Add/Remove debugging code
  • Concatenate files
  • Generate Documentation
  • Validate Code
  • Test Code
  • Minify Files
  • Deploy Files

Build tools

  • js-build-tools – easy preprocessors. Supports:
// #ifdef debugEnabled
someFunction();
// #endif

Documentation Tools

  • JSDOC
  • YUI docs
  • Docco

Linting

  • JSLint
  • JSHint (More config options)

Compressors

  • Uglify JS
  • Closure Compiler
  • YUI compressor – Deprecated

Task Runners

  • Ant (Note: Ant was probably a good advice back in 2012, but today I would just use Grunt)
    • Good blogpost on how to use Ant for JS and CSS minifcation
  • Grunt

Build types

  • Development
    • Add/Remove Debugging
    • Validate Code
    • Test Code
    • Generate Documentation
  • Testing
    • Add/Remove Debugging
    • Validate Code
    • Test Code
    • Concatenate files
    • Minify Files
  • Deployment
    • Add/Remove Debugging
    • Validate Code
    • Test Code
    • Concatenate files
    • Minify Files
    • Deploy Files

Summary

  • Use style guidelines
  • Loose coupling of layers makes changes and debugging easier
  • Good programming practices allow for easier debugging
  • Code organization and automation help to bring sanity to an otherwise crazy process

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
(Unknown)

More about Nicholas C. Zakas

http://www.nczonline.net/
@slicknet

Filed Under: JavaScript

Subscribe to this Blog via Email

New posts only. No other messages will be sent.

You can find me on LinkedIn, GitHub, Twitter or Facebook.

Comments

    Leave a Reply Cancel reply

  1. Heinrich Göbl says

    July 21, 2016 at 7:24 am

    Avoid null comparison – yes, I agree. But then how should one deal with objects not created by constructors? The trap of typeof null === 'object' makes this almost impossible. In practice when something is either an object or empty (undefined/null), IMHO it’s sufficient to write if (obj.someMember) { ... }.

    Another thought: when switching to TypeScript, which is easy and doesn’t have to be a big bang, code becomes more maintainable and many errors are detected by the compiler. Of course an article about “Maintainable JavaScript” recommending not to use JavaScript would be strange.

    Reply
  2. Yi Ze says

    July 17, 2016 at 1:57 am

    Great list but in my view these alone will not make JavaScript more maintainable. An inexperienced programmer will find a way to follow all of the above and still create lot of technical debt. I would add one more clause to the maintainable definition, which is to say, “Can withstand crap” and see what fits!

    Reply
    • fadzlan says

      July 18, 2016 at 10:36 am

      In the extreme it’s either a perfect storm of good fortune, ie. great programmers, great practices, great management, etc, or a perfect storm of bad fortunes, ie. inexperienced programmers, outdated practices, clueless management, etc.

      Normally though, our lives are somewhere in between. We just try our best so that our “good things” are enough to cancel out “bad things” in our lives. I guess this particular articles are basically adding those good things.😀

      Reply
  3. Nit says

    July 16, 2016 at 10:52 am

    Why do you use typeof value == “string” instead of typeof value === “string”?

    Reply
    • Alex Kras says

      July 16, 2016 at 2:12 pm

      Thanks, it’s a typo.

      Reply
  4. Johnd396 says

    July 13, 2014 at 7:51 pm

    Some truly select blog posts on this web site , saved to fav. gadkddggaede

    Reply
  5. Kirill Sukhomlin says

    June 8, 2014 at 11:02 pm

    Great presentation, but it worth noting, that YUI Compressor has been deprecated more than year ago.
    http://www.yuiblog.com/blog/2012/10/16/state-of-yui-compressor/

    Reply
    • Alex says

      June 10, 2014 at 1:08 am

      Thanks for the tip. I’ve updated the article.

      Reply

Trackbacks

  1. Writing Good Code is a lot Like Writing Prose | Artificia Intelligence says:
    July 11, 2017 at 5:57 am

    […] other words, as Nicholas Zakas pointed out in his talk Maintainable JavaScript, if you open an editor and it’s blank – you are writing new code, if something is already there […]

    Reply
  2. Debugging day 21: Continue button, take three – JavaScript Debugging says:
    October 7, 2016 at 11:11 am

    […] is clarity. It makes no sense to call an input handler from functions like this. I learned from Summary of Maintainable JavaScript to separate event handlers and functions. In this case, the functions are sometimes event handlers […]

    Reply
  3. Debugging Day 15: I broke switchOption – JavaScript Debugging says:
    October 7, 2016 at 10:21 am

    […] that I did, but it would be inconsistent with the way we do it on other places. I learned from maintainable JavaScript to 1. agree on a code style and stick to it and 2. solve the problem of ‘this code looks wrong […]

    Reply
  4. Useful – Mostly Tech Stuff says:
    July 19, 2016 at 7:25 pm

    […] of Maintainable JavaScript Talk by Nicholas C. […]

    Reply
  5. Javascript Weekly No.184 | ENUE Blog says:
    August 11, 2015 at 4:29 pm

    […] Summary of Maintainable JavaScript Talk by Nicholas C. Zakas […]

    Reply
  6. Кучка ссылок | Nick's Journal says:
    June 30, 2014 at 7:41 am

    […] alexkras.com/summary-of-maintainable-javascript/ — Implementing Authentication in […]

    Reply
  7. Week’s TOP Articles from the world for Web Developers (1-7 June 2014) says:
    June 12, 2014 at 8:27 am

    […] Custom Gestures — Web Fundamentals 10 Tips for Writing JavaScript without jQuery | Tutorialzine Summary of Maintainable JavaScript Talk by Nicholas C. Zakas Prefill Your Own Forms in Dev | CSS-Tricks Checking Media Queries With Javascript How to use the […]

    Reply
  8. Дайджест интересных материалов из мира веб-разработки и IT за последнюю неделю №112 (1 — 7 июня 2014) says:
    June 8, 2014 at 5:24 am

    […] Краткое изложение выступления Nicholas C. Zakas относительно … […]

    Reply

Copyright © 2019 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in