Author Archive

Talks To Help You Become A Better Front-End Engineer In 2013


  

Many of us care deeply about developing our craft. But staying up to date can be a true challenge, because the quantity of fresh information we’re regularly exposed to can be a lot to take in. 2012 has been no exception, with a wealth of evolution and refinement going on in the front end.

Great strides have been made in how we approach workflow, use abstractions, appreciate code quality and tackle the measurement and betterment of performance. If you’ve been busy and haven’t had time to catch up on the latest developments in these areas, don’t worry.

With the holiday season upon us and a little more time on our hands, I thought it would be useful to share a carefully curated list of the most relevant front-end talks I’ve found helpful this year. You certainly don’t have to read through them all, but the advice shared in them will equip you with the knowledge needed to go into the new year as a better front-end engineer.

Screenshot
Image credit: Jacob Bøtter

Baseline

Have a Strategy for Staying Up to Date

How to Stay Up to Date on Web Stuff, Chris Coyier

Part of continually developing your craft is staying up to date. Doing this is important for all professionals, and in this talk you’ll learn strategies for staying updated even when the ideas that surround the technologies we use are constantly evolving.

Screenshot

Make Sure Your Baseline for Development Is Current

A New Baseline for Front-End Developers, Rebecca Murphey

There was a time when editing files, testing them locally and simply FTP’ing them was the common workflow for a front-end developer. We would measure our abilities based on how well we could harass IE 6 into rendering pages correctly, and we generally lacked strong skills in HTML, CSS and JavaScript.

This has greatly changed over the past few years, with improvements in workflow and tooling. Front-end development is now taken more seriously, and this talk sheds light on the new baseline process for developing on the front end.

Screenshot

Understand How Browsers Work Behind the Scenes

So, You Want to Be a Front-End Engineer, David Mosher (Video)

Some would say that the browser is the most volatile development platform the world has ever known. If you’re a client-side developer, understanding how browser internals work can help you both make better decisions and appreciate the justifications behind many development best practices. In one of the best talks this year, David Mosher takes you through how browsers parse and render your pages.

Screenshot

Know What the Web Platform Now Has to Offer

The Web Can Do That!?, Eric Bidelman (Video)

The Web is constantly evolving, and keeping up with what’s new on the platform can be hard. HTML5’s new capabilities enable us to build an entirely new suite of applications with features that were simply impossible to achieve before (at least, not without the use of plugins) but are now a reality.

In this talk, my teammate Eric guides you through the bleeding edge of HTML5, focusing on solving many real-world problems. You’ll learn about media streaming, device input, modern CSS design, media capture, file I/O and more.

Screenshot

Workflow

For Web App Developers

Tooling for the Modern Web App Developer, Addy Osmani

Whether you’re using JavaScript or CoffeeScript, LESS or Sass, building an awesome Web application these days usually requires a plethora of boilerplates, frameworks and tools and a lot of glue to get them to work together. In short, you need a kick-ass utility belt.

In this talk, you’ll get an overview of the current tooling eco-system for the front-end and learn about a new tool that tries to bring together all of the pieces of this eco-system for you, called Yeoman.

Screenshot

An extended version of this talk is also available.

For Web Designers

A Modern Web Designer’s Workflow, Chris Coyier (Video)

A lot is expected from today’s Web designers. If this role defines what you do, then it’s now not just about visual design, but increasingly about building interactions. Designs need to work across different devices of varying shapes, sizes and connections, and they also need to be accessible.

As a designer, you often need to communicate and share code across teams and be familiar with many different technologies. In this talk, Chris Coyier discusses many of the amazing tools that can help things along, discussing what does what and giving a high-level view of a modern workflow.

Screenshot

For Mobile Web Developers

Mobile Web Developers Toolbelt, Pete Le Page (Video)

Building for the mobile Web requires a different mindset to the one we use when developing for desktop, and a different set of tools. Thankfully, a number of great options are available. From remote debugging to emulation, mobile browsers are offering more and more tools to make our lives easier.

In this talk, Pete Le Page takes you through a couple of tools that you can use today to make cross-platform mobile Web development easier, and then he peers into the crystal ball to see what tools the future may bring.

Screenshot

For Debugging

Secrets of the Chrome DevTools, Patrick Dubroy (Video)

Google Chrome Developer Tools provide powerful ways to understand, debug and profile Web applications. Most developers are familiar with Chrome’s basic inspection and debugging tools, but some of its most valuable features, like the Timeline and memory analysis tools, are less known.

In his demo-based walkthrough, Patrick Dubroy provides an overview of Chrome Developer Tools and an in-depth demonstration of some lesser-known features.

Screenshot

The Future

CSS

The CSS of Tomorrow, Peter Gasston

In this talk, Peter looks briefly at the state of CSS3: what you can do right now, and what you’ll be able to do in the very near future. He then looks into the long-term future, to a time when CSS3 will make possible page layouts far richer and more dynamic than we’d thought possible, and when CSS3 has taken on aspects of programming languages. This is effectively what CSS developers will be learning years from now.

Screenshot

JavaScript

The Future of JavaScript, Dave Herman

The Web platform is growing, and JavaScript is growing along with it. EcmaScript 6, the next edition of the JavaScript standard, is gearing up to be a huge step forward for Web programming. In this talk, Dave Herman discusses the exciting new features being worked on for EcmaScript 6 and how they can be used.

Screenshot

Web Applications

Web Components and the Future of Web App Development, Eric Bidelman

Web components are going to fundamentally change the way we think, build and consume Web apps. ShadowDOM, Mutation Observers, custom elements, MDV, Object.observe(), CSS — how do they all fit together?

This talk prepares you for the future of the Web platform by discussing the fundamentals of Web components and how we can use them today with frameworks such as AngularJS.

Screenshot

CSS

State of the Art

All the New CSS Hawtness, Darcy Clarke

This talk dives into some of the latest CSS implementations and specifications floating around. You’ll learn what’s here and what’s around the corner, and you’ll gain insight into why these new features will change our development workflow.

Darcy Clarke touches on modules such as paged-media, multi-columns, flex-box, filters, regions, box-sizing, masking and 3D.

Screenshot

Modularity

Your CSS Is a Mess, Jonathan Snook

We all think that CSS is easy. Take some selectors, add some properties, maybe a dash of media queries, and — presto! — you have a beautiful website. And yet, as the project changes and the team grows, we see the frustration build, with increasingly complex selectors and overuse of !important.

In this talk, Jonathan looks at common problems and solutions that will make your CSS (and your projects) easier to manage and easier to scale.

Screenshot

Pre-Processors

CSS Pre-Processors, Bermon Painter

If you haven’t jumped on the pre-processor train this year, you’re missing out. In this helpful overview of (current) popular pre-processors, Bermon Painter takes you through Stylus, LESS and Sass, with features subdivided into easy-to-learn sections of beginner, intermediate and advanced. I’ve been using mixins quite heavily this year, and I simply wouldn’t have been able to if it weren’t for projects like Sass.

Screenshot

Documentation

A Better Future With KSS, Kyle Neath

Writing maintainable CSS within a team is one of those problems that a lot of people think can be solved by writing CSS in a particular style. But in Kyle’s experience, that never works out.

In this talk, he introduces you to his latest creation, KSS. It’s a documentation and style guide format. He’ll show you why he built KSS and how it’s been helping him at GitHub to refactor its four-and-a-half year old CSS, and he’ll give you a glimpse into the future of KSS.

Screenshot

JavaScript

The Importance of Code Style

Maintainable JavaScript, Nicholas Zakas

Some say that good code is its own documentation, and the fact is that the more readable our code is, the easier it is to maintain.

Writing JavaScript for fun and writing it professionally are two different things, and in this talk by Zakas, you’ll learn practices to make JavaScript maintainable over the long run, to reduce errors and to make your code easily adaptable to future changes. It’s highly recommended reading.

Screenshot

A Modern Large-Scale App Stack

SoundCloud’s Stack, Nick Fisher

I’ve talked a lot about large-scale development in the past. It’s a non-trivial problem that’s difficult to get right, and so it’s exciting when someone working on such challenges shares their experience.

In this talk, Nick Fisher of SoundCloud discusses the company’s story of developing large-scale applications with JavaScript, not only at runtime, but also its steps to make development and deployment easier. In particular, he looks at RequireJS and Backbone, talking about how SoundCloud has used and abused each to suit its needs, sometimes in uncommon ways.

Screenshot

Rethinking Application Structure

Re-Imagining the Browser With AngularJS, Igor Minar

What if you could a write modern Web app with dramatically fewer lines of code and improve its readability and expressiveness at the same time? In case you’re wondering: no, there’s no new language to learn, just familiar old HTML and JavaScript. As a matter of fact, there are concepts for you to unlearn.

AngularJS is a client-side JavaScript Web development framework whose authors believe they’ve done something special. Instead of asking what kind of functions they could provide to make writing apps smoother, they asked, “What if the browser worked differently in a way that eliminates code and gives structure to apps?�

In this talk, you’ll get a tour of how to get the power of tomorrow’s Web platform in today’s Web applications.

Screenshot

Internationalization and i18n

Entschuldigen you, parlez vouz JavaScript, Sebastian Golasch (Video)

While JavaScript applications grow in size and complexity, there are still some white spots on the big map of Web applications: internationalization and globalization! If you´re still thinking that switching strings in and out is the way to go, you are definitely headed in the wrong direction.

In this talk, Sebastian takes you through how to spot real-world internationalization problems and how to solve them in the most elegant way.

Screenshot

I couldn’t cover internationalization without mentioning Alex Sexton, who has also spoken a great deal on this topic. His JSConf talk on client-side internationalization is available in video form if you’re interested in checking it out.

Patterns and Principles

The Plight of Pinocchio, Brandon Keepers

JavaScript is no longer a toy language, and many of our Web applications can’t function without it. Brandon states that if we are going to use JavaScript to do real things, then we need to treat it like a real language, adopting the same practices that we use with real languages. I completely agree with him.

This framework-agnostic talk takes a serious look at how we develop JavaScript applications in the real world. Despite their prototypical nature, good object-oriented programming principles are still relevant. The design patterns that we’ve grown to know and love work just as well in JavaScript as they do in any other language.

Screenshot

When to Lazy Load Scripts

How Late Is Later?, Massimiliano Marcon

Reducing the loading time of a Web application is a well-known challenge. Developers need to make sure that the browser downloads only the code that is strictly necessary to bootstrap the application, and leave the rest for later. This is what we commonly call “lazy loading.�

But when is “laterâ€�? When is the right time to lazy load? This talk shows how JavaScript code — functions and objects — can be delivered to the browser on demand, thus reducing the perceived loading time of a Web application.

Screenshot

Mobile

Building Touch-Based Interfaces

Creating Responsive HTML5 Touch Interfaces, Stephen Woods (Video | Audio)

Flickr front-end engineer Stephen Woods shares some hard-learned lessons about building responsive touch-based interfaces using HTML5 and CSS. Because our users are demanding better instant feedback from touch-based UIs, understanding how to approach this problem and avoid the pitfalls will be critical for many application developers in the future.

Screenshot

The Challenge With Scrolling

Embracing Touch: Cross-Platform Scrolling, Mark Dalgleish (Video)

Scrolling effects are a popular way to add personality to the simple act of moving down the page. Unfortunately, these effects don’t work natively on mobile devices, where the touch interaction would make these techniques more effective. In this talk, Mark looks at some ways to implement these effects within the limitations of mobile browsers.

Screenshot

Native, HTML5 and Hybrid Apps

Native, HTML5 and Hybrid Mobile Development, Eran Zinman

One of the toughest decisions every mobile developer faces is choosing a development strategy: “Should I develop a native, HTML5 or hybrid mobile app?� Over the past two years, Eran has led Conduit’s mobile client development efforts, experimenting with cross-platform development in various flavors: from complete HTML5 solutions (using PhoneGap and other technologies) to hybrid solutions to semi-hybrid solutions to fully native solutions.

In this talk, Eran shares some real-life experiences in cross-platform development, describing changes that Conduit has implemented along the way, and sharing what some of the “big players� (such as Facebook, LinkedIn and Twitter) are doing in their mobile app development.

Screenshot

Performance, Distribution and Facebook on HTML5

On the Future of Mobile Web Apps, Simon Cross

Simon looks at Facebook’s experience with and investment in the mobile Web, the issues affecting mobile Web developers and what Facebook and the industry are doing to push the mobile Web forward. Mark Zuckerberg’s comments on HTML5 were undoubtedly one of the most discussed topics in mobile this year, and I personally found these slides a good summary of Facebook’s current take on what works and what still requires improvement.

Screenshot

Tools for Mobile Debugging

Mobile Debugging, Remy Sharp

Debugging Web apps on mobile devices can be a genuine pain. Luckily, a number of tools are available today to ease the process. From remote debuggers to cross-device consoles, this talk summarizes the current state of debugging for mobile, going into more depth on debugging than Pete’s talk from earlier in the post.

Screenshot

Responsive Design Techniques

Responsive Web Design: Clever Tips and Techniques, Vitaly Friedman

Responsive Web design challenges designers to apply a new mindset to their design processes and to the techniques they use in design and coding. This talk (by Smashing Magazine’s own Vitaly Friedman) provides an overview of various practical techniques, tips and tricks that you might want to be aware of when working on a new responsive design project.

Screenshot

Web Apps

Offline Web Apps

Offline Rules, Andrew Betts (Video)

In the last couple of years, a deluge of new offline storage technologies have appeared. In this talk, Andrew looks at why they are all excellent and rubbish at the same time and why you need to use all of them, and he walks through techniques to consider when building a Web application that can load and function with no network connectivity.

But making use of client-side storage is necessary not only in order to make an app that works offline, but it can also hugely improve the experience of your website when the user actually does have connectivity.

Screenshot

State of the Art

Building Web Apps of the Future: Tomorrow, Today and Yesterday, Paul Kinlan (Audio)

The browser is an amazing runtime that can already deliver amazing apps. Paul dives into the technologies that will help you deliver Web apps that will blow your users’ socks off now and in the future.

Screenshot

Client-Side Storage

Storage in the Browser, Andrew Betts

Installed native applications can use all the space they want, but in the browser we’re much more limited. This talk explores how to make the best use of the storage technologies available to Web apps, comparing the virtues of different packaging and encoding techniques, and covering simple forms of in-browser compression that can yield surprising results.

As more apps are developed to surf over network turbulence, and to work even when completely disconnected from the network, local storage becomes ever more important.

Screenshot

Application Cache

Application Cache: Douchebag, Jake Archibald (Video)

The Application Cache is one of the cool bits of HTML5. It allows websites to work without a network connection, and it brings us much closer to native app-like behavior. However, from roundup articles and talks about HTML5, you might be left with the impression that it’s a magic bullet. Unfortunately, it isn’t; the Application Cache is, as Jake famously puts it, a douchebag.

In this talk, he looks at how to use the features of Application Cache without the horrible side effects, comparing techniques that you’d use for both a simple client-side app and a large content-driven website. He explores the many gotchas left out of most articles about Application Cache and discusses how to build your website to survive them.

Screenshot

Performance

CSS

High-Performance CSS, Paul Irish

Paul dives into the tools available in and outside of the browser to assess the performance of your CSS. Find out what’s slow (is box-shadow causing paints to be 70 milliseconds longer?) and how to fix it. Learn about about:tracing, CSS profiling and speed tracer, and get a better understanding of the browser’s internals in the process.

Screenshot

There’s also Jon Rohan’s talk about some problems related to CSS performance that were solved at GitHub. Recommended reading.

GitHub’s CSS Performance, Jon Rohan

Screenshot

Avoiding Jank

Jank-Free: In Pursuit of Smooth Web Apps, Tom Wiltzius

Building beautiful experiences on the mobile Web takes more than a good designer and fancy CSS: performance is critical for a Web app to feel fluid. Smooth animation that never drops a frame can give your app a native feel. But when animations stutter, effects lag or pages scroll slowly, we call that “jank.� This talk is about identifying jank and getting rid of it.

Screenshot

Web

Building Faster Websites, Ilya Grigorik

In this comprehensive crash course, Ilya Grigorik shares some really juicy tips on how to make the Web faster, including Google’s findings on what slows down people’s Web experience and how Chrome and other services have improved it. If you’re an engineer looking to improve the performance of your websites or apps, this talk comes highly recommended.

Screenshot

JavaScript

Breaking the JavaScript Speed Limit With V8, Daniel Clifford

Are you interested in making JavaScript run blazingly fast? If so, this talk looks at V8 under the hood to help you identify how to optimize your JavaScript. Daniel shows you how to leverage V8’s sampling profiler to eliminate performance bottlenecks and optimize JavaScript programs. He also exposes how V8 uses hidden classes and runtime-type feedback to generate efficient JIT code. A very interesting talk for performance junkies.

Screenshot

Note: Some of the optimizations mentioned in this talk are specific to V8 and may not apply to other JavaScript engines. I wrote about how to write memory-efficient JavaScript on Smashing Magazine recently, in case you’re interested in exploring the topic further.

Testing

Understanding Code Smells

Why Our Code Smells, Brandon Keepers (Video)

Odors exist for a reason, and they are usually trying to tell us something. If our code smells, it might be trying to tell us what is wrong.

Does a test case require an abundance of setting up? Maybe the code being tested is doing too much, or it is not isolated enough for the test? Does an object have an abundance of instance variables? Maybe it should be split into multiple objects? Is a view brittle? Maybe it is too tightly coupled to a model, or maybe the logic needs to be abstracted into an object that can be tested?

In this talk, Brandon walks through code from projects that he works on every day, looking for smells that indicate problems, understanding why the smells are there, what the smells are trying to tell us, and how to refactor them.

Screenshot

Current State of the Art

JavaScript Testing: The Holy Grail, Adam Hawkins (Video)

Adam talks about this Holy Grail for JavaScript developers: getting a test suite up and running fast and having multiple browsers execute the tests. Getting the Holy Grail is difficult, though, even though several tools have been created in the past in attempts to solve this problem.

Barriers to entries are everywhere. How easy is it to get going testing small parts of JavaScript functionality? What happens as your become bigger and more complex? What about headless testing? Does this process scale up to CI? Can you even do this stuff locally?

A myriad of testing tools and solutions are available, and Adam shows what’s out there and what we as a community need to do next to get the Holy Grail, to ensure a better Web experience for everyone.

Screenshot

Tip: One tool for testing that I’m loving at the moment is Testling-CI, which runs browser tests on every push.

Improving the Testability of Your Code

Writing Testable JavaScript, Rebecca Murphey (Audio)

It’s one thing to write the code that you need to write to get something working; quite another to write the code that you need to write to prove that it works — and to prove that it will continue to work as you refactor and add new features.

In her talk, Rebecca looks at what it means to write testable JavaScript code.

Screenshot

Conclusion

Time spent thinking about (and developing) your craft is time well spent. The more honed your skills are, the more opportunity you will have to become an efficient engineer.

While this list doesn’t cover every excellent talk presented this year, it hopefully offers some direction for you to accentuate your skills. Do consider reading through a few of them. Focused reading in this way will add to your value as a craftsperson and hopefully improve your daily development workflow.

With that, do enjoy the holiday season and have a fantastic new year.

(al)


© Addy Osmani for Smashing Magazine, 2012.


Performance: Writing Fast, Memory-Efficient JavaScript


  

JavaScript engines such as Google’s V8 (Chrome, Node) are specifically designed for the fast execution of large JavaScript applications. As you develop, if you care about memory usage and performance, you should be aware of some of what’s going on in your user’s browser’s JavaScript engine behind the scenes.

Whether it’s V8, SpiderMonkey (Firefox), Carakan (Opera), Chakra (IE) or something else, doing so can help you better optimize your applications. That’s not to say one should optimize for a single browser or engine. Never do that.

You should, however, ask yourself questions such as:

  • Is there anything I could be doing more efficiently in my code?
  • What (common) optimizations do popular JavaScript engines make?
  • What is the engine unable to optimize for, and is the garbage collector able to clean up what I’m expecting it to?

Dashboard Speedometer
Fast-loading Web sites — like fast cars — require the use specialized tools. Image source: dHybridcars.

There are many common pitfalls when it comes to writing memory-efficient and fast code, and in this article we’re going to explore some test-proven approaches for writing code that performs better.

So, How Does JavaScript Work In V8?

While it’s possible to develop large-scale applications without a thorough understanding of JavaScript engines, any car owner will tell you they’ve looked under the hood at least once. As Chrome is my browser of choice, I’m going to talk a little about its JavaScript engine. V8 is made up of a few core pieces.

  • A base compiler, which parses your JavaScript and generates native machine code before it is executed, rather than executing bytecode or simply interpreting it. This code is initially not highly optimized.
  • V8 represents your objects in an object model. Objects are represented as associative arrays in JavaScript, but in V8 they are represented with hidden classes, which are an internal type system for optimized lookups.
  • The runtime profiler monitors the system being run and identifies “hot” functions (i.e. code that ends up spending a long time running).
  • An optimizing compiler recompiles and optimizes the “hot” code identified by the runtime profiler, and performs optimizations such as inlining (i.e. replacing a function call site with the body of the callee).
  • V8 supports deoptimization, meaning the optimizing compiler can bail out of code generated if it discovers that some of the assumptions it made about the optimized code were too optimistic.
  • It has a garbage collector. Understanding how it works can be just as important as the optimized JavaScript.

Garbage Collection

Garbage collection is a form of memory management. It’s where we have the notion of a collector which attempts to reclaim memory occupied by objects that are no longer being used. In a garbage-collected language such as JavaScript, objects that are still referenced by your application are not cleaned up.

Manually de-referencing objects is not necessary in most cases. By simply putting the variables where they need to be (ideally, as local as possible, i.e. inside the function where they are used versus an outer scope), things should just work.

Garbage collection attempts to reclaim memory.
Garbage collection attempts to reclaim memory. Image source: Valtteri Mäki.

It’s not possible to force garbage collection in JavaScript. You wouldn’t want to do this, because the garbage collection process is controlled by the runtime, and it generally knows best when things should be cleaned up.

De-Referencing Misconceptions

In quite a few discussions online about reclaiming memory in JavaScript, the delete keyword is brought up, as some developers think you can force de-referencing using it. Never use delete. Ever. In the below example, delete o.x does a lot more harm than good behind the scenes, as it changes o‘s hidden class and makes it a generic slow object.

var o = { x: 1 }; 
delete o.x; // true 
o.x; // undefined

There are also misconceptions about how null works. Setting an object reference to null doesn’t “null” the object. It sets the object reference to null. Using o.x = null is better than using delete, but it’s probably not even necessary.

var o = { x: 1 }; 
o = null;
o; // null
o.x // TypeError

If this reference was the last reference to the object, the object is then eligible for garbage collection. If the reference was not the last reference to the object, the object is reachable and will not be garbage collected.

Another important note to be aware of is that global variables are not cleaned up by the garbage collector during the life of your page. Regardless of how long the page is open, variables scoped to the JavaScript runtime global object will stick around.

var myGlobalNamespace = {};

Globals are cleaned up when you refresh the page, navigate to a different page, close tabs or exit your browser. Function-scoped variables get cleaned up when a variable falls out of scope. When functions have exited and there aren’t any more references to it, the variable gets cleaned up.

Rules of Thumb

To give the garbage collector a chance to collect as many objects as possible as early as possible, don’t hold on to objects you no longer need. This mostly happens automatically; here are a few things to keep in mind.

  • As mentioned earlier, a better alternative to manual de-referencing is to use variables with an appropriate scope. I.e. instead of a global variable that’s nulled out, just use a function-local variable that goes out of scope when it’s no longer needed. This means cleaner code with less to worry about.
  • Ensure that you’re unbinding event listeners where they are no longer required, especially when the DOM objects they’re bound to are about to be removed
  • If you’re using a data cache locally, make sure to clean that cache or use an aging mechanism to avoid large chunks of data being stored that you’re unlikely to reuse

Functions

Next, let’s look at functions. As we’ve already said, garbage collection works by reclaiming blocks of memory (objects) which are no longer reachable. To better illustrate this, here are some examples.

function foo() {
    var bar = new LargeObject();
    bar.someCall();
}

When foo returns, the object which bar points to is automatically available for garbage collection, because there is nothing left that has a reference to it.

Compare this to:

function foo() {
    var bar = new LargeObject();
    bar.someCall();
    return bar;
}

// somewhere else
var b = foo();

We now have a reference to the object which survives the call and persists until the caller assigns something else to b (or b goes out of scope).

Closures

When you see a function that returns an inner function, that inner function will have access to the outer scope even after the outer function is executed. This is basically a closure — an expression which can work with variables set within a specific context. For example:

function sum (x) {
    function sumIt(y) {
        return x + y;
    };
    return sumIt;
}

// Usage
var sumA = sum(4);
var sumB = sumA(3);
console.log(sumB); // Returns 7

The function object created within the execution context of the call to sum can’t be garbage collected, as it’s referenced by a global variable and is still very much accessible. It can still be executed via sumA(n).

Let’s look at another example. Here, can we access largeStr?

var a = function () {
    var largeStr = new Array(1000000).join('x');
    return function () {
        return largeStr;
    };
}();

Yes, we can, via a(), so it’s not collected. How about this one?

var a = function () {
    var smallStr = 'x';
    var largeStr = new Array(1000000).join('x');
    return function (n) {
        return smallStr;
    };
}();

We can’t access it anymore and it’s a candidate for garbage collection.

Timers

One of the worst places to leak is in a loop, or in setTimeout()/setInterval(), but this is quite common.

Consider the following example.

var myObj = {
    callMeMaybe: function () {
        var myRef = this;
        var val = setTimeout(function () { 
            console.log('Time is running out!'); 
            myRef.callMyMaybe();
        }, 1000);
    }
};

If we then run:

myObj.callMeMaybe();

to begin the timer, we can see every second “Time is running out!” If we then run:

myObj = null;

The timer will still fire. myObj won’t be garbage collected as the closure passed to setTimeout has to be kept alive in order to be executed. In turn, it holds references to myObj as it captures myRef. This would be the same if we’d passed the closure to any other function, keeping references to it.

It is also worth keeping in mind that references inside a setTimeout/setInterval call, such as functions, will need to execute and complete before they can be garbage collected.

Be Aware Of Performance Traps

It’s important never to optimize code until you actually need to. This can’t be stressed enough. It’s easy to see a number of micro-benchmarks showing that N is more optimal than M in V8, but test it in a real module of code or in an actual application, and the true impact of those optimizations may be much more minimal than you were expecting.

Speed trap.
Doing too much can be as harmful as not doing anything. Image source: Tim Sheerman-Chase.

Let’s say we want to create a module which:

  • Takes a local source of data containing items with a numeric ID,
  • Draws a table containing this data,
  • Adds event handlers for toggling a class when a user clicks on any cell.

There are a few different factors to this problem, even though it’s quite straightforward to solve. How do we store the data? How do we efficiently draw the table and append it to the DOM? How do we handle events on this table optimally?

A first (naive) take on this problem might be to store each piece of available data in an object which we group into an array. One might use jQuery to iterate through the data and draw the table, then append it to the DOM. Finally, one might use event binding for adding the click behavior we desire.

Note: This is NOT what you should be doing

var moduleA = function () {

    return {

        data: dataArrayObject,

        init: function () {
            this.addTable();
            this.addEvents();
        },

        addTable: function () {

            for (var i = 0; i < rows; i++) {
                $tr = $('<tr></tr>');
                for (var j = 0; j < this.data.length; j++) {
                    $tr.append('<td>' + this.data[j]['id'] + '</td>');
                }
                $tr.appendTo($tbody);
            }

        },
        addEvents: function () {
            $('table td').on('click', function () {
                $(this).toggleClass('active');
            });
        }

    };
}();

Simple, but it gets the job done.

In this case however, the only data we’re iterating are IDs, a numeric property which could be more simply represented in a standard array. We also know that DocumentFragment and native DOM methods are more optimal than using jQuery for our table generation, and, of course, that event delegation is typically more performant than binding each td individually.

Adding in these changes results in some good (expected) performance gains. Event delegation provides decent improvement over simply binding, and opting for documentFragment was a real booster.

var moduleD = function () {

    return {

        data: dataArray,

        init: function () {
            this.addTable();
            this.addEvents();
        },
        addTable: function () {
            var td,td;
            for (var i = 0; i < rows; i++) {
                tr = document.createElement('tr');
                for (var j = 0; j < this.data.length; j++) {
                    td = document.createElement('td');
                    td.appendChild(document.createTextNode(this.data[j]));

                    frag2.appendChild(td);
                }
                tr.appendChild(frag2);
                frag.appendChild(tr);
            }
            tbody.appendChild(frag);
        },
        addEvents: function () {
            $('table').on('click', 'td', function () {
                $(this).toggleClass('active');
            });
        }

    };

}();

We might then look to other ways of improving performance. It’s possible we came across a test case showing that the prototype pattern is more optimal than the module pattern, or that JavaScript templating frameworks are super-optimized. (Sometimes they are, but use them because they make for readable code. Also, precompile!). Let’s test and find out.

moduleG = function () {};

moduleG.prototype.data = dataArray;
moduleG.prototype.init = function () {
    this.addTable();
    this.addEvents();
};
moduleG.prototype.addTable = function () {
    var template = _.template($('#template').text());
    var html = template({'data' : this.data});
    $tbody.append(html);
};
moduleG.prototype.addEvents = function () {
   $('table').on('click', 'td', function () {
       $(this).toggleClass('active');
   });
};

var modG = new moduleG();

As it turns out, in this case the performance benefits are extremely negligible. Opting for templating and prototypes didn’t really offer anything more than what we had before. That said, performance isn’t really the reason modern developers use either of these things — it’s the readability, inheritance model and maintainability they bring to your codebase.

More complex problems include efficiently drawing images using canvas and manipulating pixel data with or without typed arrays

Always give micro-benchmarks a close lookover before exploring their use in your application. Some of you may recall the JavaScript templating shoot-off and the extended shoot-off that followed. You want to make sure that tests aren’t being impacted by constraints you’re unlikely to see in real world applications — test optimizations together in actual code.

V8 Optimization Tips

Whilst detailing every V8 optimization is outside the scope of this article, there are certainly many tips worth noting. Keep these in mind and you’ll reduce your chances of writing unperformant code.

  • Certain patterns will cause V8 to bail out of optimizations. A try-catch, for example, will cause such a bailout. For more information on what functions can and can’t be optimized, you can use the --trace-bailout file.js with the d8 shell utility that comes with V8.
  • If you care about speed, try very hard to keep your functions monomorphic, i.e. make sure that variables (including properties, arrays and function parameters) only ever contain objects with the same hidden class. For example, don’t do this:
function add(x, y) { 
   return x+y;
} 

add(1, 2); 
add('a',''b'); 
add(my_custom_object, undefined);
  • Don’t load from uninitialized or deleted elements. This won’t make a difference in output, but it will make things slower.
  • Don’t write enormous functions, as they are more difficult to optimize

For more tips, watch Daniel Clifford’s Google I/O talk Breaking the JavaScript Speed Limit with V8 as it covers these topics well. Optimizing For V8 — A Series is also worth a read.

Objects Vs. Arrays: Which Should I Use?

  • If you want to store a bunch of numbers, or a list of objects of the same type, use an array.
  • If what you semantically need is an object with a bunch of properties (of varying types), use an object with properties. That’s pretty efficient in terms of memory, and it’s also pretty fast.
  • Integer-indexed elements, regardless of whether they’re stored in an array or an object, are much faster to iterate over than object properties.
  • Properties on objects are quite complex: they can be created with setters, and with differing enumerability and writability. Items in arrays aren’t able to be customized as heavily — they either exist or they don’t. At an engine level, this allows for more optimization in terms of organizing the memory representing the structure. This is particularly beneficial when the array contains numbers. For example, when you need vectors, don’t define a class with properties x, y, z; use an array instead..

There’s really only one major difference between objects and arrays in JavaScript, and that’s the arrays’ magic length property. If you’re keeping track of this property yourself, objects in V8 should be just as fast as arrays.

Tips When Using Objects

  • Create objects using a constructor function. This ensures that all objects created with it have the same hidden class and helps avoid changing these classes. As an added benefit, it’s also slightly faster than Object.create()
  • There are no restrictions on the number of different object types you can use in your application or on their complexity (within reason: long prototype chains tend to hurt, and objects with only a handful of properties get a special representation that’s a bit faster than bigger objects). For “hot” objects, try to keep the prototype chains short and the field count low.

Object Cloning
Object cloning is a common problem for app developers. While it’s possible to benchmark how well various implementations work with this type of problem in V8, be very careful when copying anything. Copying big things is generally slow — don’t do it. for..in loops in JavaScript are particularly bad for this, as they have a devilish specification and will likely never be fast in any engine for arbitrary objects.

When you absolutely do need to copy objects in a performance-critical code path (and you can’t get out of this situation), use an array or a custom “copy constructor” function which copies each property explicitly. This is probably the fastest way to do it:

function clone(original) {
  this.foo = original.foo;
  this.bar = original.bar;
}
var copy = new clone(original);

Cached Functions in the Module Pattern
Caching your functions when using the module pattern can lead to performance improvements. See below for an example where the variation you’re probably used to seeing is slower as it forces new copies of the member functions to be created all the time.

Note, however, that in most browsers, this will really only render it as performant as it would be just using prototypes. A good gotcha worth knowing, otherwise!

Performance improvements when using the module pattern.
Performance improvements when using the module pattern.

Here is a test of prototype versus module pattern performance

// Module pattern
Klass = function() {
  var foo = function() {
        log('foo');
      },
      bar = function() {
        log('bar');
      };

  return {foo: foo, bar: bar}
}

var i = 1000,
    objs = [];
while (i--) {
  var o = new Klass()
  objs.push(new Klass());
  o.bar;
  o.foo;
}

// Module pattern with cached functions
var FooFunction = function() {
  log('foo');
};
var BarFunction = function() {
  log('bar');
};

Klass = function() {
  return {foo: FooFunction, bar: BarFunction}
}

var i = 1000,
    objs = [];
while (i--) {
  var o = new Klass()
  objs.push(new Klass());
  o.bar;
  o.foo;
}

Tips When Using Arrays

Next let’s look at a few tips for arrays. In general, don’t delete array elements. It would make the array transition to a slower internal representation. When the key set becomes sparse, V8 will eventually switch elements to dictionary mode, which is even slower.

Array Literals
Array literals are useful because they give a hint to the VM about the size and type of the array. They’re typically good for small to medium sized arrays.

// Here V8 can see that you want a 4-element array containing numbers:
var a = [1, 2, 3, 4];

// Don't do this:
a = []; // Here V8 knows nothing about the array
for(var i = 1; i <= 4; i++) {
     a.push(i);
}

Storage of Single Types Vs. Mixed Types
It’s never a good idea to mix values of different types (e.g. numbers, strings, undefined or true/false) in the same array (i.e. var arr = [1, “1�, undefined, true, “true�])

Test of type inference performance

As we can see from the results, the array of ints is the fastest.

Sparse Arrays vs. Full Arrays
When you use sparse arrays, be aware that accessing elements in them is much slower than in full arrays. That’s because V8 doesn’t allocate a flat backing store for the elements if only a few of them are used. Instead, it manages them in a dictionary, which saves space, but costs time on access.

Test of sparse arrays versus full arrays.

The full array sum and sum of all elements on an array without zeros were actually the fastest. Whether the full array contains zeroes or not should not make a difference.

Packed Vs. Holey Arrays
Avoid “holes” in an array (created by deleting elements or a[x] = foo with x > a.length). Even if only a single element is deleted from an otherwise “full” array, things will be much slower.

Test of packed versus holey arrays.

Pre-allocating Arrays Vs. Growing As You Go
Don’t pre-allocate large arrays (i.e. greater than 64K elements) to their maximum size, instead grow as you go. Before we get to the performance tests for this tip, keep in mind that this is specific to only some JavaScript engines.

Test of empty literal versus pre-allocated arrays in various browsers.
Test of empty literal versus pre-allocated array in various browsers.

Nitro (Safari) actually treats pre-allocated arrays more favorably. However, in other engines (V8, SpiderMonkey), not pre-allocating is more efficient.

Test of pre-allocated arrays.

// Empty array
var arr = [];
for (var i = 0; i < 1000000; i++) {
    arr[i] = i;
}

// Pre-allocated array
var arr = new Array(1000000);
for (var i = 0; i < 1000000; i++) {
    arr[i] = i;
}

Optimizing Your Application

In the world of Web applications, speed is everything. No user wants a spreadsheet application to take seconds to sum up an entire column or a summary of their messages to take a minute before it’s ready. This is why squeezing every drop of extra performance you can out of code can sometimes be critical.

An old phone on the screen of an iPad.
Image source: Per Olof Forsberg.

While understanding and improving your application performance is useful, it can also be difficult. We recommend the following steps to fix performance pain points:

  • Measure it: Find the slow spots in your application (~45%)
  • Understand it: Find out what the actual problem is (~45%)
  • Fix it! (~10%)

Some of the tools and techniques recommended below can assist with this process.

Benchmarking

There are many ways to run benchmarks on JavaScript snippets to test their performance — the general assumption being that benchmarking is simply comparing two timestamps. One such pattern was pointed out by the jsPerf team, and happens to be used in SunSpider‘s and Kraken‘s benchmark suites:

var totalTime,
    start = new Date,
    iterations = 1000;
while (iterations--) {
  // Code snippet goes here
}
// totalTime → the number of milliseconds taken 
// to execute the code snippet 1000 times
totalTime = new Date - start;

Here, the code to be tested is placed within a loop and run a set number of times (e.g. six). After this, the start date is subtracted from the end date to find the time taken to perform the operations in the loop.

However, this oversimplifies how benchmarking should be done, especially if you want to run the benchmarks in multiple browsers and environments. Garbage collection itself can have an impact on your results. Even if you’re using a solution like window.performance, you still have to account for these pitfalls.

Regardless of whether you are simply running benchmarks against parts of your code, writing a test suite or coding a benchmarking library, there’s a lot more to JavaScript benchmarking than you might think. For a more detailed guide to benchmarking, I highly recommend reading JavaScript Benchmarking by Mathias Bynens and John-David Dalton.

Profiling

The Chrome Developer Tools have good support for JavaScript profiling. You can use this feature to detect what functions are eating up the most of your time so that you can then go optimize them. This is important, as even small changes to your codebase can have serious impacts on your overall performance.

Profiles panel in Chrome Developer Tools.
Profiles Panel in Chrome Developer Tools.

Profiling starts with obtaining a baseline for your code’s current performance, which can be discovered using the Timeline. This will tell us how long our code took to run. The Profiles tab then gives us a better view into what’s happening in our application. The JavaScript CPU profile shows us how much CPU time is being used by our code, the CSS selector profile shows us how much time is spent processing selectors and Heap snapshots show how much memory is being used by our objects.

Using these tools, we can isolate, tweak and reprofile to gauge whether changes we’re making to specific functions or operations are improving performance.

The profile tab gives information about your code's performance.
The Profile tab gives you information about your code’s performance.

For a good introduction to profiling, read JavaScript Profiling With The Chrome Developer Tools, by Zack Grossbart.

Tip: Ideally, you want to ensure that your profiling isn’t being affected by extensions or applications you’ve installed, so run Chrome using the --user-data-dir <empty_directory> flag. Most of the time, this approach to optimization testing should be enough, but there are times when you need more. This is where V8 flags can be of help.

Avoiding Memory Leaks — Three Snapshot Techniques for Discovery

Internally at Google, the Chrome Developer Tools are heavily used by teams such as Gmail to help us discover and squash memory leaks.

Memory statistics in Chrome Developer Tools.
Memory statistics in Chrome Developer Tools.

Some of the memory statistics that our teams care about include private memory usage, JavaScript heap size, DOM node counts, storage clearing, event listener counts and what’s going on with garbage collection. For those familiar with event-driven architectures, you might be interested to know that one of the most common issues we used to have were listen()’s without unlisten()’s (Closure) and missing dispose()’s for objects that create event listeners.

Luckily the DevTools can help locate some of these issues, and Loreena Lee has a fantastic presentation available documenting the “3 snapshot” technique for finding leaks within the DevTools that I can’t recommend reading through enough.

The gist of the technique is that you record a number of actions in your application, force a garbage collection, check if the number of DOM nodes doesn’t return to your expected baseline and then analyze three heap snapshots to determine if you have a leak.

Memory Management in Single-Page Applications

Memory management is quite important when writing modern single-page applications (e.g. AngularJS, Backbone, Ember) as they almost never get refreshed. This means that memory leaks can become apparent quite quickly. This is a huge trap on mobile single-page applications, because of limited memory, and on long-running applications like email clients or social networking applications. With great power comes great responsibility.

There are various ways to prevent this. In Backbone, ensure you always dispose old views and references using dispose(). This function was recently added, and removes any handlers added in the view’s ‘events’ object, as well as any collection or model listeners where the view is passed as the third argument (callback context). dispose() is also called by the view’s remove(), taking care of the majority of basic memory cleanup needs when the element is cleared from the screen. Other libraries like Ember clean up observers when they detect that elements have been removed from view to avoid memory leaks.

Some sage advice from Derick Bailey:

“Other than being aware of how events work in terms of references, just follow the standard rules for manage memory in JavaScript and you’ll be fine. If you are loading data in to a Backbone collection full of User objects you want that collection to be cleaned up so it’s not using anymore memory, you must remove all references to the collection and the individual objects in it. Once you remove all references, things will be cleaned up. This is just the standard JavaScript garbage collection rule.”

In his article, Derick covers many of the common memory pitfalls when working with Backbone.js and how to fix them.

There is also an helpful tutorial available for debugging memory leaks in Node by Felix Geisendörfer worth reading, especially if it forms a part of your broader SPA stack.

Minimizing Reflows

When a browser has to recalculate the positions and geometrics of elements in a document for the purpose of re-rendering it, we call this reflow. Reflow is a user-blocking operation in the browser, so it’s helpful to understand how to improve reflow time.

Chart of reflow time.
Chart of reflow time.

You should batch methods that trigger reflow or that repaints, and use them sparingly. It’s important to process off DOM where possible. This is possible using DocumentFragment, a lightweight document object. Think of it as a way to extract a portion of a document’s tree, or create a new “fragment” of a document. Rather than constantly adding to the DOM using nodes, we can use document fragments to build up all we need and only perform a single insert into the DOM to avoid excessive reflow.

For example, let’s write a function that adds 20 divs to an element. Simply appending each new div directly to the element could trigger 20 reflows.

function addDivs(element) {
  var div;
  for (var i = 0; i < 20; i ++) {
    div = document.createElement('div');
    div.innerHTML = 'Heya!';
    element.appendChild(div);
  }
}

To work around this issue, we can use DocumentFragment, and instead, append each of our new divs to this. When appending to the DocumentFragment with a method like appendChild, all of the fragment’s children are appended to the element triggering only one reflow.

function addDivs(element) {
  var div; 
  // Creates a new empty DocumentFragment.
  var fragment = document.createDocumentFragment();
  for (var i = 0; i < 20; i ++) {
    div = document.createElement('a');
    div.innerHTML = 'Heya!';
    fragment.appendChild(div);
  }
  element.appendChild(fragment);
}

You can read more about this topic at Make the Web Faster,
JavaScript Memory Optimization and Finding Memory Leaks.

JavaScript Memory Leak Detector

To help discover JavaScript memory leaks, two of my fellow Googlers (Marja Hölttä and Jochen Eisinger) developed a tool that works with the Chrome Developer Tools (specifically, the remote inspection protocol), and retrieves heap snapshots and detects what objects are causing leaks.

A tool for detecting JavaScript memory leaks.
A tool for detecting JavaScript memory leaks.

There’s a whole post on how to use the tool, and I encourage you to check it out or view the Leak Finder project page.

Some more information: In case you’re wondering why a tool like this isn’t already integrated with our Developer Tools, the reason is twofold. It was originally developed to help us catch some specific memory scenarios in the Closure Library, and it makes more sense as an external tool (or maybe even an extension if we get a heap profiling extension API in place).

V8 Flags for Debugging Optimizations & Garbage Collection

Chrome supports passing a number of flags directly to V8 via the js-flags flag to get more detailed output about what the engine is optimizing. For example, this traces V8 optimizations:

"/Applications/Google Chrome/Google Chrome" --js-flags="--trace-opt --trace-deopt --trace-bailout"

Windows users will want to run `chrome.exe --js-flags="--trace-opt --trace-deopt --trace-bailout"

When developing your application, the following V8 flags can be used.

  • trace-opt – log names of optimized functions.
  • trace-deopt – log a list of code it had to deoptimize while running.
  • trace-bailout – find out where the optimizer is skipping code because it can’t figure something out.
  • trace-gc – logs a tracing line on each garbage collection.

V8’s tick-processing scripts mark optimized functions with an * (asterisk) and non-optimized functions with ~ (tilde).

If you’re interested in learning more about V8′s flags and how V8′s internals work in general, I strongly recommend looking through Vyacheslav Egorov’s excellent post on V8 internals, which summarizes the best resources available on this at the moment.

High-Resolution Time and Navigation Timing API

High Resolution Time (HRT) is a JavaScript interface providing the current time in sub-millisecond resolution that isn’t subject to system clock skews or user adjustments. Think of it as a way to measure more precisely than we’ve previously had with new Date and Date.now(). This is helpful when we’re writing performance benchmarks.

High Resolution Time (HRT) provides the current time in sub-millisecond resolution.
High Resolution Time (HRT) provides the current time in sub-millisecond resolution.

HRT is currently available in Chrome (stable) as window.performance.webkitNow(), but the prefix is dropped in Chrome Canary, making it available via window.performance.now(). Paul Irish has written more about HRT in a post on HTML5Rocks.

So, we now know the current time, but what if we wanted an API for accurately measuring performance on the web?

Well, one is now also available in the Navigation Timing API. This API provides a simple way to get accurate and detailed time measurements that are recorded while a webpage is loaded and presented to the user. Timing information is exposed via window.performance.timing, which you can simply use in the console:

Timing information is shown in the console.
Timing information is shown in the console.

Looking at the data above, we can extract some very useful information. For example, network latency is responseEnd-fetchStart, the time taken for a page load once it’s been received from the server is loadEventEnd-responseEnd and the time taken to process between navigation and page load is loadEventEnd-navigationStart.

As you can see above, a perfomance.memory property is also available that gives access to JavaScript memory usage data such as the total heap size.

For more details on the Navigation Timing API, read Sam Dutton’s great article Measuring Page Load Speed With Navigation Timing.

about:memory and about:tracing

about:tracing in Chrome offers an intimate view of the browser’s performance, recording all of Chrome’s activities across every thread, tab and process.

about:tracing offers an intimate view of the browser’s performance.
About:Tracing offers an intimate view of the browser’s performance.

What’s really useful about this tool is that it allows you to capture profiling data about what Chrome is doing under the hood, so you can properly adjust your JavaScript execution, or optimize your asset loading.

Lilli Thompson has an excellent write-up for games developers on using about:tracing to profile WebGL games. The write-up is also useful for general JavaScripters.

Navigating to about:memory in Chrome is also useful as it shows the exact amount of memory being used by each tab, which is helpful for tracking down potential leaks.

Conclusion

As we’ve seen, there are many hidden performance gotchas in the world of JavaScript engines, and no silver bullet available to improve performance. It’s only when you combine a number of optimizations in a (real-world) testing environment that you can realize the largest performance gains. But even then, understanding how engines interpret and optimize your code can give you insights to help tweak your applications.

Measure It. Understand it. Fix it. Rinse and repeat.

Measuring.
Image source: Sally Hunter.

Remember to care about optimization, but stop short of opting for micro-optimization at the cost of convenience. For example, some developers opt for .forEach and Object.keys over for and for in loops, even though they’re slower, for the convenience of being able to scope. Do make sanity calls on what optimizations your application absolutely needs and which ones it could live without.

Also, be aware that although JavaScript engines continue to get faster, the next real bottleneck is the DOM. Reflows and repaints are just as important to minimize, so remember to only touch the DOM if it’s absolutely required. And do care about networking. HTTP requests are precious, especially on mobile, and you should be using HTTP caching to reduce the size of assets.

Keeping all of these in mind will ensure that you get the most out of the information from this post. I hope you found it helpful!

Credits

This article was reviewed by Jakob Kummerow, Michael Starzinger, Sindre Sorhus, Mathias Bynens, John-David Dalton and Paul Irish.

Image source of picture on front page.

(cp) (jc)


© Addy Osmani for Smashing Magazine, 2012.



The Smashing Guide To Moving The Web Forward





 



 


Many of us rely on open source tools, technologies and standards to help improve the work we do on a daily basis. None of this would however be possible without the hard work, commitment and dedication that others, just like you, have invested in giving back to the Web community over the past two decades.

Modernizr, HTML5 Boilerplate and jQuery are just a few examples of well known projects which were born from a desire to put something out there that could help others on the Web do more. These projects evolved because developers started using them and thought, “Hey, I could do something to help make this better. I bet it could save someone else’s time if I shared this with the world.”

Web standards like CSS3, HTML5 and the foundations of the Web as we know them would also not have been possible without people (just like readers of this post) spending time researching use cases, writing proposals, implementing features and catering to existing and future requirements that could be used by everyone. When you think about it, both standards and open source projects have had a large hand to play in the Web as we know it today.

In this article I’d like to talk about how you can help give back to the Web and a new project that seeks to make this process easier: MoveTheWebForward.org. If you’ve ever thought about contributing to the community but weren’t sure just how, I hope this serves as a good starting point for your journey.

Why Help Move The Web Forward?

In most cases, developers and designers that contribute back do so because of an inherent passion or desire to either improve an open source project, Web standards or the quantity of educational material freely available online.

What you get back from this is (in my opinion) worth every minute of effort.

Contributing to open source projects, you can learn more about the intricacies of programming languages, libraries and standards implementations than you probably could if you were just been a passive user. This can help you gain a better appreciation for how the Web is built, but also improve the quality of the development work you do as a part of your job.

Whilst not the reason most people do it, open source involvement can also often lead to more fulfilling jobs (and occasionally more pay). Demonstrating you have passion (and skills) in a focused area can help highlight you to recruiters at companies where those skills are highly valued.

Finally, involvement can help improve your knowledge, whether it’s simply writing tutorials about standards for others, actually being involved in submitting patches or feature implementations to browser vendors and libraries or contributing to discussions in standards mailing lists (which I’ll discuss in greater detail shortly).

“For me, open source is not about giving back, but its more about being sociable with the developers you admire. I really like forming small groups to work on projects and challenges together, or just like-minded folks that chitchat and passively learn new skills regularly.

The community has given me back great friends and I think we’ve all found more ways to be fulfilled by the work we create.”

 —  Paul Irish, HTML5 Boilerplate, Modernizr, jQuery team

Contributing

1. What can you do and how much time can you contribute?
Before we look at what you can do to contribute back to the Web, ask yourself three very simple questions: What are your strongest skill-sets? How you might these be used in an open source project? How much time and effort would you like to contribute to giving back?

Understandably, a lot of us have full-time jobs and it can be tricky sometimes trying to fit in extra side-projects into our schedules. The great thing about the Web is that there’s never too little or too much time that you can spend moving it forward.

10 minutes is enough to help someone stuck on a Web-development problem and an hour here or there is enough to greatly improve existing open source projects. If you have the desire to give back, anything is possible.

2. Pick a project or Web standard/specification you would like to work on
Once you have some rough ideas of much time you can contribute, you’ll need to decide on the project, standards group or area you would like to help with. The good news is that there’s a great new initiative to help with this called MoveTheWebForward.org (MWF), driven by some of the talented people that brought us HTML5 Boilerplate.

MWF is a project that aims to make it easy for anyone to get started contributing to the open source community.

Whether you’re just diving into Web development, or are have been doing it back since tables were cool for layout, there are a number ways for you to give back to the community. MWF makes it easy to help anyone find ways to contribute back to the Web platform by giving you a list of ideas, resources and guides to get you started.

Not sure what projects to look at or where to find lazy-Web requests you can get done in an afternoon? Not a problem. The site breaks down almost all aspects of open source contribution and even separates things based on your level of experience. Regardless of whether you’re a CSS wizard, a JavaScript ninja, or a C++ hacker wanting to play with WebKit there’s something on MWF that everyone can help with.

Don’t see a project that applies to you on there yet? Don’t worry. It’s being updated everyday and other members of the community can submit pull requests to add new things to it. You may also find it helpful reviewing what libraries and technologies you regularly use personally, whether it be a CSS feature like psuedo-selectors or a JavaScript library like Modernizr or jQuery. Beyond the basics, you may have some insights or ideas for how these could be improved in some subtle way.

Do you feel the implementation of a particular feature isn’t quite as usable as it could be? Are there circumstances where a solution just doesn’t give developers everything they need? The learnings you’ve obtained whilst using things on a day to day basis are something you can share with a project to help improve it.

Take a look at MoveTheWebForward.org each week and if you’re up for it, consider committing to getting a small task done that can push the Web forward.

3. What would you like your role in the project to be?
Most open source projects (and standards groups) have a number of key areas that they require assistance with. In no chronological order these are:

  • Core development
  • Discussions / Mailing lists
  • Documentation
  • Bug submissions triage
  • Operations
  • Testing
  • Site & UI Design
  • Developer Evangelism
  • Support

Depending on the project there may also be areas such as ‘specification writing’ that are necessary in order for features to be discussed before they are implemented.

Core Development

Core development generally involves development of a core set of features, fixes or rewrites for JavaScript libraries, and browser feature implementations or patches when it comes to Web standards.

Whilst beginners won’t generally be directly discouraged from trying to get involved with core development, it’s more often intermediate and advanced users of libraries or features that are better equipped to optimally implement code that is efficient, performs well and passes unit tests.

“I love open source. I’ve been hooked on jQuery since John Resig accepted my first patch in January 2006. It’s been at the center of several profitable projects that I’ve built. Contributing to both jQuery’s code and documentation just seems like the right way to pay that forward.”

 —  Dave Methvin, jQuery team

If you’re interested in getting involved with core development, I suggest spending time familiarizing yourself with:

  • The build/setup instructions for the open source project you wish to contribute to
  • How the project is structured so you can later experiment with making patches and running tests
  • The project contribution guide. Most open source projects these days are hosted on GitHub. This means that filing patches is usually as straight-forward as filing a pull request, but make sure to follow the project’s guidelines on doing this. At jQuery, we require developers to file a ticket in our bug tracker to accompany pull requests but it’s a subtle step that we cover in the contribution guide.
  • Where current contributors congregate to discuss issues, features and patches — with Web standards or libraries this could be a mailing list or an IRC channel. Mozilla has dedicated channels for people wishing to contribute to the MDN as do jQuery and many, many other open source projects.

“Whether you’re contributing to existing projects or open-sourcing projects of your own, giving back to the community is a great way to learn about Cool New Stuff™.”

 —  Mathias Bynens. jsPerf, HTML5 Boilerplate

Discussions & Mailing Lists

Standards Mailing Lists

We all know that Web standards are important. They help ensure the code we write works across different technologies, for people of different abilities and most importantly across all browsers. If you have an interest in pushing the Web forward by getting involved with the standards process, there are a number of different mailing lists you can subscribe to (and participate in) should you have particularly strong feelings about the direction particular technologies or features should be taking.

These mailing lists include public-html, public-webapps, es-discuss, www-style, public-fx and WHATWG. I recommend spending time familiarizing yourself with how contributors to these lists approach discussion as you’ll want to ensure your posts are read rather than ignored – specifically, research proposals, read spec wikis where available and ask other posters for their input offline if you’re unsure about anything.

Note: Chapter 2 of Mark Pilgrim’s HTML5 book contain an excellent discussion of how standards get pushed through mailing lists. It also covers some of the evolution of standards through history and is a recommended read for those interested in grasping how the process works. You can read it for free online here: http://diveintohtml5.info/past.html

The jQuery Standards Team

While many of us would like to see change, the reality is due to time restrictions and lengthy formal processes we’re not always able to participate in standards discussions, get involved with writing specifications and contribute to meetings about the future of features. This can sometimes make it difficult for Web developers to have a voice.

Another problem is that for those that do get involved with the process, it can often feel like participating on a particular thread in standards mailing lists has a limited impact because the Web community is so fragmented. There’s also a lot of assumed knowledge required of existing discussions, decisions and historical context that can make it a little more challenging to get involved.

The jQuery project have set out to try changing this. They want you to have a voice in how the future of the Web is shaped which is why they created the jQuery Standards team. The standards team listens to suggestions or feedback you may have about current specs and if there’s sufficient interest in making changes related to your concerns, they’ll file tickets on your behalf in the appropriate format.

For more information see: https://github.com/jquery/standards

Code/Project Mailing Lists

Mailing lists for code projects (e.g jQuery, Dojo) tend to work quite similarly to those for Web standards. The only real differences are that discussions can sometimes be more fast-paced and generally target the resolution of features or fixes being targeted for a specific library rather than something as broad as a standard.

You don’t have to be someone that implements library code to be able to get involved with these discussions, but it does help having a good level of familiarity with both the library, alternatives to it and the general space being worked on. As per my early suggestion, spend a little time analyzing the best way to jump in with suggestions or ideas to increase the chances of having a positive impact on the conversation.

Documentation

When most developers think about getting involved with open source, their first thought is usually about writing code that can one day be used by many others.Whilst it’s true that implementations are of course important, documentation is an equally if not more important part of the release process.

Think about it: when you first learn about a new specification that’s been implemented or about some new framework that’s just been released, your first port of call is to look at the documentation or the getting started guide so you can figure out just how to use it. Without this documentation, most projects (and indeed, specs) would be nowhere near as popular or widely used as they are today.

The great thing about documentation is that (unlike full-blown patches or implementations), your contributions can be as small or as large as your time permits. I’ve seen developers contribute simple one line changes to documentation whilst others have provided the equivalent of complete chapters of written docs because they wanted to make it easier for others to understand how everything works. If you’re good at writing, consider giving docs a try.

Writing docs is also a great way to increase your knowledge about how to use the software or tool you’re writing it for. If you feel comfortable using a particular project, consider looking at the bugs files on their trackers. This can offer insight into what confuses users and you can try writing out documentation for such workflows or actions that are unclear.

The barrier of entry is a little lower than core development and there are many well known open source projects that could use your help in this area.

Bug Triage (Issue Moderation)

Most open source projects (including frameworks like Modernizr and browsers such as WebKit) have their own issue or bug trackers. These are typically used as a central location where users can submit issues, feature requests and track the progress of what’s currently being addressed. As projects become more widely used, the number of issues received incrementally grows and there becomes a need for these issues to be moderated. Reasons issues may need to be moderated include being:

  • Invalid
    In many cases, users will simply submit issues with a project or specification without spending enough time debugging their solution. Sorting the invalid tickets from the valid ones makes it easier for core developers to focus on addressing the important ones.
  • Duplicates
    The issue may have been previously submitted. This is easy to discover as the majority of trackers have their own search options.
  • Patch welcome
    Where an issue is acknowledged but is beyond the scope (or time-constraints) of a project to patch itself.
  • Won’t or Can’t fix
    There are issues users may submit which a project may admit is a valid problem, but which may not be currently possible to fix, either due to the direction the project is taking or the broader implications it may have on a codebase.

Moderators are usually required to help narrow down issues to a list of (valid) confirmed issues and feature requests. The great thing about being involved in bug triage is that you’re regularly required to evaluate code samples and establish why a bug may or may not in fact be, valid.

“Contributing to the development of open source software, such as jQuery and Popcorn.js, is my way of ensuring that the future is awesome – in both the things people create and the tools that they’ll use to create them.”

 —  Rick Waldron. jQuery team, Popcorn.js

You’ll often find yourself writing short solutions that address the problem as a workaround and the knowledge you build up from these can greatly help avoid the same problems if you run into them in other projects or at work.

Operations

Larger open source projects often have to deal with millions of requests for downloading their library every single day. Even when offering a CDN-hosted version (like we do at jQuery), they still have a large quantity of requests coming in to access their sites, documentation pages and official tutorials. None of these would be able to cope under strain without the hard work that experienced ops people have to offer.

“Being involved in operations has not only given me the opportunity to contribute and sharpen my skills with git, writing tests and streamlining processes, it’s also allowed me to meet some incredibly talented people and make fantastic friends. Contributing to open source has made me better. Period.”

 —  Dan Heberden, jQuery team

Operations (ops) also take care of some of the smaller day to day tasks like granting permissions for new contributors wishing to access different parts of a site, setting up scripts to help automate and streamline tasks and generally ensuring the visible public face of a project stays online. If you have strong ops skills, feel free to reach out to projects (both small and large) as they likely wouldn’t mind some more assistance, either now or at some point in the future.

Testing

Implementations of new browser and library features require an extensive amount of testing prior to being released. This covers everything from ensuring 100% unit test coverage is reached, tests are written (or provided) for any patches submitted and where applicable, tests are run across all browsers, environments and devices your particular project targets. If you’re a stiffler for ensuring code is stable prior to being pushed to end-users, you may be interested in helping out with testing efforts. Speak to current contributors to the project to find out their current need for members looking specifically at this area.

Site & UI Design

Did you know that at projects like HTML5 Boilerplate and jQuery, there are dedicated designers that just focus on ensuring site layouts and UI components look at best as possible in every browser? Every open source site or group, from the W3C to JavaScript libraries generally have front-facing websites and it’s often the case that if a redesign or site maintenance isn’t already in the pipe-line, they could use your help.

“Working on open source projects means you have the skills of several people to tap on. It is a great place to learn Web development, creating workflows that work for collaboration. Moreover, it’s safe – it’s not like you’ll get fired for testing things out. The projects I contribute to are directed towards problems I struggled with myself and wish other designers had.”

 —  Divya Manian, HTML5 Boilerplate

Before you approach a project about helping them with any design work, talk to the members to see what their plans are or what they’d ideally like someone to work on. They may ask you to present a mockup of concepts you may have to establish if they’d like to get you involved with their current design team or in taking on your ideas for one of their next versions. A good to strong knowledge of HTML/CSS and a little JavaScript is always useful to have, but even if you just design in Photoshop that’s another piece of work someone else in the community could take further.

Evangelism & Support

The role of technical evangelists varies quite a lot in open source projects. Its goals can include:

  • Supporting developers in the community by providing assistance, answering questions and making it as easy as possible for developers to solve problems they may be running into (doing so via IRC, Twitter or forums is quite common).
  • Working with developers in the community to help understand why particular standards, browsers, libraries or tools should be used and can make developer’s lives easier.
  • Writing tutorials, creating screencasts and building demos that help educate others.
  • Generally speaking on behalf of the project at events to further enhance awareness about the project’s goals and offerings.
  • If you enjoy helping people solve problems or have a passion for writing (but aren’t a big fan of writing documentation), consider giving evangelism a try.

Share Knowledge, Share Experiences and Build New Things

Beyond assisting with the goals of a specific code project or standards working group, there’s a an array of other useful things you could be doing to help push the Web forward.

Building
Many of the most popular open source projects today once started out as tools and workarounds that a developer or designer worked on to satisfy a personal need. If you love hacking on code, please consider sticking your work up on GitHub and sharing it with the rest of the world. There may be many others (just like you) that your work could end up helping or inspiring it’s a great feeling knowing that you’ve saved someone else from dealing with the same headaches you once had to yourself.

Note: GitHub offer a regular free class on the ‘basics’ that you can sign up for. You can also get a free copy of ‘Pro Git’ that covers most of the fundamentals.

Blogging
Although I’m involved in open source projects, my biggest contribution to the Web is still in my day to day technical writing. Teaching through this medium is a great learning tool and you’ll often find yourself learning more as you write and research about the topics you’re conveying.

Remember that your words can be a very powerful tool for pushing education on the Web forward. For this reason I encourage you to consider writing about what you do and learn — write tutorials, create demos, post gists, write essays.

“After being repeatedly nudged by people to start writing about changes to WebKit and Chromium, which I had been monitoring for a long time already, I wrote my first article back in August 2010.

To date, 64 articles have been published and many more people are aware of and get involved in the implementation of cutting-edge features at both projects. I myself am now part of the Google Chrome and WebKit teams, focusing on improving both the browser as the Web, doing that which I love to do.”

 —  Peter Beverloo, Google Chrome team

Don’t be afraid to make mistakes (because that’s how we all improve). It’s absolutely okay for you to not be a complete expert or authority on a topic. Share what you do know because it has the potential to help many other developers and designers out there. Reach out to others in the community if you don’t know something — ask questions and prompt conversations.

Contribute to the MDN
For those interested in getting involved with writing, it’s okay if you don’t have your own blog. Almost any designer or developer with HTML, CSS or JavaScript skills can also contribute back to the Web through the MDN (Mozilla Developer Network).

The Mozilla Developer Network, also known as MDN.

The MDN is a community of developers building resources to improve the Web, regardless of what browser or platform you’re using. Anyone can contribute to it as the entire site is a wiki (just like Wikipedia). There are sections that detail specs, pages that are just tutorials and others that are just guides to quirks that are useful to be aware of when using particular browser features.

“When I learned about Web standards not much was available out there. The Mozilla Developer Network was one of the first resources I kept going back to when I was stuck. The reason why it still is that way is that it is a living resource that anyone is invited to edit and keep clean.

It is pretty rewarding to be part of this and knowing that what you put on the Web is part of something that by definition is there to keep the Web free, open, and make it easier for the next generation of Web makers not to have to make the same mistakes we did to build something good for the Web.”

 —  Christian Heillman, Mozilla

To give you an example, here’s a page I fleshed out during one of the MDN sprints with (reliable) links to get started with learning Web development: Introduction to Web development. Simple, right? It’s nothing more than an organized page of links, but prior to the new learning section on the MDN site being launched, it helped developers and designers get started with basic fundamentals when they were unsure where to look.

Mozilla evangelists regularly hang out in #mdn on irc.mozilla.org (IRC) and are always happy to help new contributors get started if you have any questions. Consider giving it a try!

Conclusion

That’s it for this guide. I’ll be sure to update it if there’s anything I’ve missed out on, but I hope it inspires others to consider giving back to the Web platform. Remember to check out MoveTheWebForward.org if you’re interested in picking a task you can start working on today. Together, we can help move the Web forward.

Further Reading

With special thanks to Divya Manian, Nicolas Gallagher and Paul Irish. Images courtesy of the 56 Geeks project.

(vf) (il)


© Addy Osmani for Smashing Magazine, 2011.


Lessons From A Review Of JavaScript Code





 



 


Before we start, I’d like to pose a question: when was the last time you asked someone to review your code? Reviewing code is possibly the single best technique to improve the overall quality of your solutions, and if you’re not actively taking advantage of it, then you’re missing out on identifying bugs and hearing suggestions that could make your code better.

None of us write 100% bug-free code all of the time, so don’t feel there’s a stigma attached to seeking help. Some of the most experienced developers in our industry, from framework authors to browser developers, regularly request reviews of their code from others; asking whether something could be tweaked should in no way be considered embarrassing. Reviews are a technique like any other and should be used where possible.

Today we’ll look at where to get your code reviewed, how to structure your requests, and what reviewers look for. I was recently asked to review some code for a new JavaScript application, and thought I’d like to share some of my feedback, because it covers some JavaScript fundamentals that are always useful to bear in mind.

Introduction

Reviewing code goes hand in hand with maintaining strong coding standards. That said, standards don’t usually prevent logical errors or misunderstandings about the quirks of a programming language, whether it’s JavaScript, Ruby, Objective-C or something else. Even the most experienced developers can make these kinds of mistakes, and reviewing code can greatly assist with catching them.

The first reaction most of us have to criticism is to defend ourselves (or our code), and perhaps lash back. While criticism can be slightly demoralizing, think of it as a learning experience that spurs us to do better and to improve ourselves; because in many cases, once we’ve calmed down, it actually does.

Also remember that no one is obliged to provide feedback on your work, and if the comments are indeed constructive, then be grateful for the time spent offering the input.

Reviews enable us to build on the experience of others and to benefit from a second pair of eyes. And at the end of the day, they are an opportunity for us to write better code. Whether we take advantage of them is entirely our choice.

Where Can I Get My Code Reviewed?

Often the most challenging part is actually finding an experienced developer who you trust to do the review. Below are some places where you can request others to review your code (sometimes in other languages, too).

  • JSMentors
    JSMentors is a mailing list that discusses everything to do with JavaScript (including Harmony), and a number of experienced developers are on its review panel (including JD Dalton, Angus Croll and Nicholas Zakas). These mentors might not always be readily available, but they do their best to provide useful, constructive feedback on code that’s been submitted. If you’re looking for assistance with a specific JavaScript framework beyond vanilla JavaScript, the majority of frameworks and libraries have mailing lists or forums that you can post to and that might provide a similar level of assistance.
  • freenode IRC
    Many chat rooms here are dedicated both to discussing the JavaScript language and to requests for help or review. The most popular rooms are obviously named, and #javascript is particularly useful for generic JavaScript requests, while channels such as #jquery and #dojo are better for questions and requests related to particular libraries and frameworks.
  • Code Review (beta)
    You would be forgiven for confusing Code Review with StackOverflow, but it’s actually a very useful, broad-spectrum, subjective tool for getting peer review of code. While on StackOverflow you might ask the question “Why isn’t my code working?,� Code Review is more suited to questions like “Why is my code so ugly?� If you still have any doubt about what it offers, I strongly recommend checking out the FAQs.
  • Twitter
    This might sound odd, but at least half of the code that I submit for review is through social networks. Social networks work best, of course, if your code is open source, but trying them never hurts. The only thing I suggest is to ensure that the developers who you follow and interact with are experienced; a review by a developer with insufficient experience can sometimes be worse than no review at all, so be careful!
  • GitHub + reviewth.is
    We all know that GitHub provides an excellent architecture for reviewing code. It comes with commits, file and line comments, update notifications, an easy way to track forks of gits and repositories, and more. All that’s missing is a way to actually initiate reviews. A tool called reviewth.is attempts to rectify that by giving you a post-commit hook that helps to automate this process, so changes that get posted in the wild have a clear #reviewthis hash tag, and you can tag any users who you wish to review your updates. If many of your colleagues happen to develop in the same language as you do, this set-up can work well for code reviews sourced closer to home. One workflow that works well with this (if you’re working on a team or on a collaborative project) is to perform your own work in a topic branch in a repository and then send through pull requests on that branch. Reviewers would examine the changes and commits and could then make line-by-line and file-by-file comments. You (the developer) would then take this feedback and do a destructive rebase on that topic branch, re-push it, and allow the review cycle to repeat until merging them would be acceptable.

How Should I Structure My Review Requests?

The following are some guidelines (based on experience) on how to structure your requests for code reviews, to increase the chances of them being accepted. You can be more liberal with them if the reviewer is on your team; but if the reviewer is external, then these might save you some time:

  • Isolate what you would like to be reviewed; ensure that it can be easily run, forked and commented; be clear about where you think improvements could be made; and, above all, be patient.
  • Make it as easy as possible for the reviewer to look at, demo and change your code.
  • Don’t submit a ZIP file of your entire website or project; very few people have the time to go through all of this. The only situation in which this would be acceptable is if your code absolutely required local testing.
  • Instead, isolate and reduce what you would like to be reviewed on jsFiddle, on jsbin or in a GitHub gist. This will allow the reviewer to easily fork what you’ve provided and to show changes and comments on what can be improved. If you would prefer a “diffâ€� between your work and any changes they’ve recommended, you might also be interested in PasteBin, which supports this.
  • Similarly, don’t just submit a link to a page and ask them to “View sourceâ€� in order to see what can be improved. On websites with a lot of scripts, this task would be challenging and lowers the chances of a reviewer agreeing to help. No one wants to work to find what you want reviewed.
  • Clearly indicate where you personally feel the implementation could be improved. This will help the reviewer quickly home in on what you’re most interested in having reviewed and will save them time. Many reviewers will still look at other parts of the code you’ve submitted regardless, but at least help them prioritize.
  • Indicate what (if any) research you’ve done into techniques for improving the code. The reviewer might very well suggest the same resources, but if they’re aware that you already know of them, then they might offer alternative suggestions (which is what you want).
  • If English isn’t your first language, there’s no harm in saying so. When other developers inform me of this, I know whether to keep the language in my review technical or simple.
  • Be patient. Some reviews take several days to get back to me, and nothing’s wrong with that. Other developers are usually busy with other projects, and someone who agrees to schedule a look at your work is being kind. Be patient, don’t spam them with reminders, and be understanding if they get delayed. Doing this sometimes pay off, because the reviewer can provide even more detailed feedback when they have more time.

What Should Code Reviews Provide?

Jonathan Betz, a former developer at Google, once said that a code review should ideally address six things:

  1. Correctness
    Does the code do everything it claims?
  2. Complexity
    Does it accomplish its goals in a straightforward way?
  3. Consistency
    Does it achieve its goals consistently?
  4. Maintainability
    Could the code be easily extended by another member of the team with a reasonable level of effort?
  5. Scalability
    Is the code written in such a way that it would work for both 100 users and 10,000? Is it optimized?
  6. Style
    Does the code adhere to a particular style guide (preferably one agreed upon by the team if the project is collaborative)?

While I agree with this list, expanding it into an action guide of what reviewers should practically aim to give developers would be useful. So, reviewers should do the following:

  • Provide clear comments, demonstrate knowledge, and communicate well.
  • Point out the shortfalls in an implementation (without being overly critical).
  • State why a particular approach isn’t recommended, and, if possible, refer to blog posts, gists, specifications, MDN pages and jsPerf tests to back up the statement.
  • Suggest alternative solutions, either in a separate runnable form or integrated in the code via a fork, so that the developer can clearly see what they did wrong.
  • Focus on solutions first, and style second. Suggestions on style can come later in the review, but address the fundamental problem as thoroughly as possible before paying attention to this.
  • Review beyond the scope of what was requested. This is entirely at the reviewer’s discretion, but if I notice issues with other aspects of a developer’s implementation, then I generally try to advise them on how those, too, might be improved. I’ve yet to receive a complaint about this, so I assume it’s not a bad thing.

Collaborative Code Reviews

Although a review by one developer can work well, an alternative approach is to bring more people into the process. This has a few distinct advantages, including reducing the load on individual reviewers and exposing more people to your implementation, which could potentially lead to more suggestions for improvements. It also allows a reviewer’s comments to be screened and corrected if they happen to make a mistake.

To assist the group, you may wish to employ a collaborative tool to allow all reviewers to simultaneously inspect and comment on your code. Luckily, a few decent ones out there are worth checking out:

  • Review Board
    This Web-based tool is available for free under the MIT license. It integrates with Git, CVS, Mercurial, Subversion and a number of other source-control systems. Review Board can be installed on any server running Apache or lighttpd and is free for personal and commercial use.
  • Crucible
    This tool by Australian software company Atlassian is also Web-based. It’s aimed at the enterprise and works best with distributed teams. Crucible facilitates both live review and live commenting and, like Review Board, integrates with a number of source-control tools, including Git and Subversion.
  • Rietveld
    Like the other two, Rietveld also supports collaborative review, but it was actually written by the creator of Python, Guido van Rossum. It is designed to run on Google’s cloud service and benefits from Guido’s experience writing Mondrian, the proprietary app that Google uses internally to review its code.
  • Others
    A number of other options for collaborative code review weren’t created for that purpose. These include CollabEdit (free and Web-based) and, my personal favorite, EtherPad (also free and Web-based).


(Image Source: joelogon)

Lessons From A JavaScript Code Review

On to the review.

A developer recently wrote in, asking me to review their code and provide some useful suggestions on how they might improve it. While I’m certainly not an expert on reviewing code (don’t let the above fool you), here are the problems and solutions that I proposed.

Problem 1

Problem: Functions and objects are passed as arguments to other functions without any type validation.

Feedback: Type validation is an essential step in ensuring that you’re working only with input of a desired type. Without sanitization checks in place, you run the risk of users passing in just about anything (a string, a date, an array, etc.), which could easily break your application if you haven’t developed it defensively. For functions, you should do the following at a minimum:

  1. Test to ensure that arguments being passed actually exist,
  2. Do a typeof check to prevent the app from executing input that is not a valid function at all.
if (callback && typeof callback === "function"){
    /* rest of your logic */
}else{
    /* not a valid function */
}

Unfortunately, a simple typeof check isn’t enough on its own. As Angus Croll points out in his post “Fixing the typeof operator,� you need to be aware of a number of issues with typeof checking if you’re using them for anything other than functions.

For example, typeof null returns object, which is technically incorrect. In fact, when typeof is applied to any object type that isn’t a function, it returns object, not distinguishing between Array, Date, RegEx or whatever else.

The solution is to use Object.prototype.toString to call the underlying internal property of JavaScript objects known as [[Class]], the class property of the object. Unfortunately, specialized built-in objects generally overwrite Object.prototype.toString, but you can force the generic toString function on them:

Object.prototype.toString.call([1,2,3]); //"[object Array]"

You might also find Angus’s function below useful as a more reliable alternative to typeof. Try calling betterTypeOf() against objects, arrays and other types to see what happens.

function betterTypeOf( input ){
    return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1];
}

Here, parseInt() is being blindly used to parse an integer value of user input, but no base is specified. This can cause issues.

In JavaScript: The Good Parts, Douglas Crockford refers to parseInt() as being dangerous. Although you probably know that passing it a string argument returns an integer, you should also ideally specify a base or radix as the second argument, otherwise it might return unexpected output. Take the following example:

parseInt('20');       // returns what you expect, however…
parseInt('020');      // returns 16
parseInt('000020');   // returns 16
parseInt('020', 10);  // returns 20 as we've specified the base to use

You’d be surprised by how many developers omit the second argument, but it happens quite regularly. Remember that your users (if permitted to freely enter numeric input) won’t necessarily follow standard number conventions (because they’re crazy!). I’ve seen 020, ,20, ;'20 and many other variations used, so do your best to parse as broad a range of inputs as possible. The following tricks to using parseInt() are occasionally better:

Math.floor("020");   // returns 20
Math.floor("0020");  //returns 20
Number("020");  //returns 20
Number("0020"); //returns 20
+"020"; //returns 20

Problem 2

Problem: Checks for browser-specific conditions being met are repeated throughout the code base (for example, feature detection, checks for supported ES5 features, etc.).

Feedback: Ideally, your code base should be as DRY as possible, and there are some elegant solutions to this problem. For example, you might benefit from the load-time configuration pattern here (also called load-time and init-time branching). The basic idea is that you test a condition only once (when the application loads) and then access the result of that test for all subsequent checks. This pattern is commonly found in JavaScript libraries that configure themselves at load time to be optimized for a particular browser.

This pattern could be implemented as follows:

var tools = {
    addMethod: null,
    removeMethod: null
};

if(/* condition for native support */){
    tools.addMethod = function(/* params */){
        /* method logic */
    }
}else{
    /* fallback - eg. for IE */
    tools.addMethod = function(/* */){
        /* method logic */
    }
}

The example below demonstrates how this can be used to normalize getting an XMLHttpRequest object.

var utils = {
    getXHR: null
};

if(window.XMLHttpRequest){
    utils.getXHR = function(){
        return new XMLHttpRequest;
    }
}else if(window.ActiveXObject){
    utils.getXHR = function(){
        /* this has been simplified for example sakes */
        return new ActiveXObject(’Microsoft.XMLHTTP’);
    }
}

For a great example, Stoyan Stefanov applies this to attaching and removing event listeners cross-browser, in his book JavaScript Patterns:

var utils = {
    addListener: null,
    removeListener: null
};
// the implementation
if (typeof window.addEventListener === ’function’) {
    utils.addListener = function ( el, type, fn ) {
        el.addEventListener(type, fn, false);
    };
    utils.removeListener = function ( el, type, fn ) {
        el.removeEventListener(type, fn, false);
    };
} else if (typeof document.attachEvent === ’function’) { // IE
    utils.addListener = function ( el, type, fn ) {
        el.attachEvent(’on’ + type, fn);
    };
    utils.removeListener = function ( el, type, fn ) {
        el.detachEvent(’on’ + type, fn);
    };
} else { // older browsers
    utils.addListener = function ( el, type, fn ) {
        el[’on’ + type] = fn;
    };
    utils.removeListener = function ( el, type, fn ) {
        el[’on’ + type] = null;
    };
}

Problem 3

Problem: The native Object.prototype is being extended regularly.

Feedback: Extending native types is generally frowned upon, and few (if any) popular code bases should dare to extend Object.prototype. The reality is that there is not likely a situation in which you absolutely need to extend it in this way. In addition to breaking the object-as-hash tables in JavaScript and increasing the chance of naming collisions, it’s generally considered bad practice, and modifying it should only be a last resort (this is quite different from extending your own custom object properties).

If for some reason you do end up extending the object prototype, ensure that the method doesn’t already exist, and document it so that the rest of the team is aware why it’s necessary. You can use the following code sample as a guide:

if(typeof Object.prototype.myMethod != ’function’){
    Object.prototype.myMethod = function(){
        //implem
    };
}

Juriy Zaytsev has a great post on extending native and host objects, which may be of interest.

Problem 4

Problem: Some of the code is heavily blocking the page because it’s either waiting on processes to complete or data to load before executing anything further.

Feedback: Page-blocking makes for a poor user experience, and there are a number of ways to work around it without impairing the application.

One solution is to use “deferred execution� (via promises and futures). The basic idea with promises is that, rather than issuing blocking calls for resources, you immediately return a promise for a future value that will eventually be fulfilled. This rather easily allows you to write non-blocking logic that can be run asynchronously. It is common to introduce callbacks into this equation that execute once the request completes.

I’ve written a relatively comprehensive post on this with Julian Aubourg, if you’re interested in doing this through jQuery, but it can of course be implemented with vanilla JavaScript as well.

Micro-framework Q offers a CommonJS-compatible implementation of promises and futures that is relatively comprehensive and can be used as follows:

/* define a promise-only delay function that resolves when a timeout completes */
function delay(ms) {
    var deferred = Q.defer();
    setTimeout(deferred.resolve, ms);
    return deferred.promise;
}

/* usage of Q with the 'when' pattern to execute a callback once delay fulfils the promise */
Q.when(delay(500), function () {
        /* do stuff in the callback */
});

If you’re looking for something more basic that can be read through, then here is Douglas Crockford’s implementation of promises:

function make_promise() {
  var status = ’unresolved’,
      outcome,
      waiting = [],
      dreading = []; 

  function vouch( deed, func ) {
    switch (status) {
    case ’unresolved’:
      (deed === ’fulfilled’ ? waiting : dreading).push(func);
      break;
    case deed:
      func(outcome);
      break;
    }
  };

  function resolve( deed, value ) {
    if (status !== ’unresolved’) {
      throw new Error(’The promise has already been resolved:’ + status);
    }
    status = deed;
    outcome = value;
    (deed == ’fulfilled’ ? waiting : dreading).forEach(function (func) {
      try {
        func(outcome);
      } catch (ignore) {}
    });
    waiting = null;
    dreading = null;
  };

  return {
    when: function ( func ) {
      vouch(’fulfilled’, func);
    },
    fail: function ( func ) {
      vouch(’smashed’, func);
    },
    fulfill: function ( value ) {
      resolve(’fulfilled’, value);
    },
    smash: function ( string ) {
      resolve(’smashed’, string);
    },
    status: function () {
      return status;
    }
  };
};

Problem 5

Problem: You’re testing for explicit numeric equality of a property using the == operator, but you should probably be using === instead

Feedback: As you may or may not know, the identity == operator in JavaScript is fairly liberal and considers values to be equal even if they’re of completely different types. This is due to the operator forcing a coercion of values into a single type (usually a number) prior to performing any comparison. The === operator will, however, not do this conversion, so if the two values being compared are not of the same type, then === will just return false.

The reason I recommend considering === for more specific type comparison (in this case) is that == is known to have a number of gotchas and is considered to be unreliable by many developers.

You might also be interested to know that in abstractions of the language, such as CoffeeScript, the == operator is completely dropped in favor of === beneath the hood due to the former’s unreliability.

Rather than take my word for it, see the examples below of boolean checks for equality using ==, some of which result in rather unexpected outputs.

3 == "3" // true
3 == "03" // true
3 == "0003" // true
3 == "+3" //true
3 == [3] //true
3 == (true+2) //true
’ \t\r\n ’ == 0 //true
"\t\r\n" == 0 //true
"\t" == 0 // true
"\t\n" == 0 // true
"\t\r" == 0 // true
" " == 0 // true
" \t" == 0 // true
" \ " == 0 // true
" \r\n\ " == 0 //true

The reason that many of the (stranger) results in this list evaluate to true is because JavaScript is a weakly typed language: it applies type coercion wherever possible. If you’re interested in learning more about why some of the expressions above evaluate to true, look at the Annotated ES5 guide, whose explanations are rather fascinating.

Back to the review. If you’re 100% certain that the values being compared cannot be interfered with by the user, then proceed with using the == operator with caution. Just remember that === covers your bases better in the event of an unexpected input.

Problem 6

Problem: An uncached array length is being used in all for loops. This is particularly bad because you’re using it when iterating through an HTMLCollection.

Here’s an example:

for( var i=0; i<myArray.length;i++ ){
    /* do stuff */
}

Feedback: The problem with this approach (which I still see a number of developers using) is that the array length is unnecessarily re-accessed on each loop’s iteration. This can be very slow, especially when working with HTMLCollections (in which case, caching the length can be anywhere up to 190 times faster than repeatedly accessing it, as Nicholas C. Zakas mentions in his book High-Performance JavaScript). Below are some options for caching the array length.

/* cached outside loop */
var len = myArray.length;
for ( var i = 0; i < len; i++ ) {
}

/* cached inside loop */
for ( var i = 0, len = myArray.length; i < len; i++ ) {
}

/* cached outside loop using while */
var len = myArray.length;
while (len--) {
}

A jsPerf test that compares the performance benefits of caching the array length inside and outside the loop, using prefix increments, counting down and more is also available, if you would like to study which performs the best.

Problem 7

Problem: jQuery’s $.each() is being used to iterate over objects and arrays, in some cases while for is being used in others.

Feedback: In jQuery, we have two ways to seamlessly iterate over objects and arrays. The generic $.each iterates over both of these types, whereas $.fn.each() iterates over a jQuery object specifically (where standard objects can be wrapped with $() should you wish to use them with the latter). While the lower-level $.each performs better than $.fn.each(), both standard JavaScript for and while loops perform much better than either, as proven by this jsPerf test. Below are some examples of loop alternatives that also perform better:

/* jQuery $.each */
$.each(a, function() {
 e = $(this);
});

/* classic for loop */
var len = a.length;
for ( var i = 0; i < len; i++ ) {
    //if this must be a jQuery object do..
    e = $(a[i]);
    //otherwise just e = a[i] should suffice
};

/* reverse for loop */
for ( var i = a.length; i-- ) {
    e = $(a[i]);
}

/* classic while loop */
var i = a.length;
while (i--) {
    e = $(a[i]);
}

/* alternative while loop */
var i = a.length - 1;

while ( e = a[i--] ) {
    $(e)
};

You might find Angus Croll’s post on “Rethinking JavaScript for Loops� an interesting extension to these suggestions.

Given that this is a data-centric application with a potentially large quantity of data in each object or array, you should consider a refactor to use one of these. From a scalability perspective, you want to shave off as many milliseconds as possible from process-heavy routines, because these can build up when hundreds or thousands of elements are on the page.

Problem 8

Problem: JSON strings are being built in-memory using string concatenation.

Feedback: This could be approached in more optimal ways. For example, why not use JSON.stringify(), a method that accepts a JavaScript object and returns its JSON equivalent. Objects can generally be as complex or as deeply nested as you wish, and this will almost certainly result in a simpler, shorter solution.

var myData = {};
myData.dataA = [’a’, ’b’, ’c’, ’d’];
myData.dataB = {
    ’animal’: ’cat’,
    ’color’: ’brown’
};
myData.dataC = {
    ’vehicles’: [{
        ’type’: ’ford’,
        ’tint’: ’silver’,
        ’year’: ’2015’
    }, {
        ’type’: ’honda’,
        ’tint’: ’black’,
        ’year’: ’2012’
    }]
};
myData.dataD = {
    ’buildings’: [{
        ’houses’: [{
            ’streetName’: ’sycamore close’,
            ’number’: ’252’
        }, {
            ’streetName’: ’slimdon close’,
            ’number’: ’101’
        }]
    }]
};
console.log(myData); //object
var jsonData = JSON.stringify(myData);

console.log(jsonData);
/*
{"dataA":["a","b","c","d"],"dataB":{"animal":"cat","color":"brown"},"dataC":{"vehicles":[{"type":"ford","tint":"silver","year":"2015"},{"type":"honda","tint":"black","year":"2012"}]},"dataD":{"buildings":[{"houses":[{"streetName":"sycamore close","number":"252"},{"streetName":"slimdon close","number":"101"}]}]}}
 */

As an extra debugging tip, if you would like to pretty-print JSON in your console for easier reading, then the following extra arguments to stringify() will achieve this:

JSON.stringify({ foo: "hello", bar: "world" }, null, 4);

Problem 9

Problem: The namespacing pattern used is technically invalid.

Feedback: While namespacing is implemented correctly across the rest of the application, the initial check for namespace existence is invalid. Here’s what you currently have:

if ( !MyNamespace ) {
  MyNamespace = { };
}

The problem is that !MyNamespace will throw a ReferenceError, because the MyNamespace variable was never declared. A better pattern would take advantage of boolean conversion with an inner variable declaration, as follows:

if ( !MyNamespace ) {
  var MyNamespace = { };
}

//or
var myNamespace = myNamespace || {};

// Although a more efficient way of doing this is:
// myNamespace || ( myNamespace = {} );
// jsPerf test: http://jsperf.com/conditional-assignment

//or
if ( typeof MyNamespace == ’undefined’ ) {
  var MyNamespace = { };
}

This could, of course, be done in numerous other ways. If you’re interested in reading about more namespacing patterns (as well as some ideas on namespace extension), I recently wrote “Essential JavaScript Namespacing Patterns.� Juriy Zaytsev also has a pretty comprehensive post on namespacing patterns.

Conclusion

That’s it. Reviewing code is a great way to enforce and maintain quality, correctness and consistency in coding standards at as high a level as possible. I strongly recommend that all developers give them a try in their daily projects, because they’re an excellent learning tool for both the developer and the reviewer. Until next time, try getting your code reviewed, and good luck with the rest of your project!

(al) (il)


© Addy Osmani for Smashing Magazine, 2011.


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress