Nicholas C. Zakas's Blog, page 15

March 13, 2012

It's time to start using JavaScript strict mode

ECMAScript 5 introduced strict mode to JavaScript. The intent is to allow developers to opt-in to a "better" version of JavaScript, where some of the most common and egregious errors are handled differently. For a while, I was skeptical, especially with only one browser (Firefox) initially supporting strict mode. Fast forward to today, every major browser supports strict mode in their latest version, including Internet Explorer 10 and Opera 12. It's time to start using strict mode.


What does it do?

Strict mode makes a lot of changes to how JavaScript runs, and I group these into two categories: obvious and subtle. The subtle changes aim to fix subtle problems, and I'm not going to delve into those here; if you're interested in those details, please see Dmitry Soshnikov's excellent, ECMA-262-5 in Detail. Chapter 2. Strict Mode[1]. I'm far more interested in talking about the obvious changes: the ones you should know about before using strict mode, and the ones that will most likely help you the most.


Before getting into specific features, keep in mind that one of the goals of strict mode is to allow for faster debugging of issues. The best way to help developers debug is to throw errors when certain patterns occur, rather than silently failing or behaving strangely (which JavaScript does today outside of strict mode). Strict mode code throws far more errors, and that's a good thing, because it quickly calls to attention things that should be fixed immediately.


Eliminates with

To begin, strict mode eliminates the with statement. It is now considered invalid JavaScript syntax and will throw a syntax error when it appears in strict mode code. So first step to using strict mode: make sure you're not using with.


// Causes a syntax error in strict mode
with (location) {
alert(href);
}
Prevents accidental globals

Next, variables must be declared before they can be assigned to. Without strict mode, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common errors in JavaScript. In strict mode, attempting to do so throws an error.


// Throws an error in strict mode
(function() {

someUndeclaredVar = "foo";

}());

Eliminates this coercion

Another important change is a this-value of null or undefined is no longer coerced to the global. Instead, this remains its original value, and so may cause some code depending on the coercion to break. For example:


window.color = "red";
function sayColor() {
alert(this.color);
}

// Throws an error in strict mode, "red" otherwise
sayColor();

// Throws an error in strict mode, "red" otherwise
sayColor.call(null);

Basically, the this-value must be assigned a value or else it remains undefined. That means constructors accidentally called without new are also affected:


function Person(name) {
this.name = name;
}

// Error in strict mode
var me = Person("Nicholas");

In this code, this is undefined when the Person constructor is called without new. Since you can't assign a property to undefined, this code throws an error. In non-strict mode, this would be coerced to the global and so name would be assigned as a global variable.


No duplicates

It can be quite easy to duplicate properties in objects or named arguments in functions if you've been doing a lot of coding. Strict mode throws an error when it comes across either pattern:


// Error in strict mode - duplicate arguments
function doSomething(value1, value2, value1) {
//code
}

// Error in strict mode - duplicate properties
var object = {
foo: "bar",
foo: "baz"
};

These are both syntax errors and so the error is thrown before the code is executed.


Safer eval()

Even though eval() wasn't removed, it has undergone some changes in strict mode. The biggest change is that variables and functions declared inside of an eval() statement are no longer created in the containing scope. For example:


(function() {

eval("var x = 10;");

// Non-strict mode, alerts 10
// Strict mode, throws an error because x is undeclared
alert(x);

}());

Any variables or functions created inside of eval() stay inside of eval(). You can, however, return a value from eval() if you wish to pass a value back out:


(function() {

var result = eval("var x = 10, y = 20; x + y");

// Works in strict and non-strict mode (30)
alert(result);

}());

Errors for immutables

ECMAScript 5 also introduced the ability to modify property attributes, such as setting a property as read only or freezing an entire object's structure. In non-strict mode, attempting to modify an immutable property fails silently. You've probably run into this issue with some native APIs. Strict mode ensures that an error is thrown whenever you try to modify an object or object property in a way that isn't allowed.


var person = {};
Object.defineProperty(person, "name" {
writable: false,
value: "Nicholas"
});

// Fails silently in non-strict mode, throws error in strict mode
person.name = "John";

In this example, the name property is set to read only. In non-strict mode, assigning to name fails silently; in strict mode, an error is thrown.


Note: I very strongly encourage you to use strict mode if you're using any of the ECMAScript attribute capabilities. If you're changing the mutability of objects, you'll run into a lot of errors that will fail silently in non-strict mode.


How do you use it?

Strict mode is very easily enabled in modern browsers using the following pragma:


"use strict";

Even though this simple looks like a string that isn't assigned to a variable, it actually instructs conforming JavaScript engines to switch into strict mode. You can use it either globally or within a function. That being said, you should never use it globally. Using the pragma globally means that any code within the same file also runs in strict mode.


// Don't do this
"use strict";

function doSomething() {
// this runs in strict mode
}

function doSomethingElse() {
// so does this
}

This may not seem like a big deal, however, it can cause big problems in our world of aggressive script concatenation. All it takes is one script to include the pragma globally for every script its concatenated with to be switch into strict mode (potentially revealing errors you never would have anticipated).


For that reason, it's best to only use strict mode inside of functions, such as:


function doSomething() {
"use strict";
// this runs in strict mode
}

function doSomethingElse() {
// this doesn't run in strict mode
}

If you want strict mode to apply to more than one function, use an immediately-invoked function expression (IIFE):


(function() {

"use strict";

function doSomething() {
// this runs in strict mode
}

function doSomethingElse() {
// so does this
}
}());
Conclusion

I strongly recommend everyone start using strict mode now. There are enough browsers supporting it that strict mode will legitimately help save you from errors you didn't even know where in your code. Make sure you don't include the pragma globally, but use IIFEs as frequently as you like to apply strict mode to as much code as possible. Initially, there will be errors you've never encountered before – this is normal. Make sure you do a fair amount of testing after switching to strict mode to make sure you've caught everything. Definitely don't just throw "use strict" in your code and assume there are no errors. The bottom line is that it's time to start using this incredibly useful language feature to write better code.


References

ECMA-262-5 in Detail. Chapter 2. Strict Mode by Dmitry Soshnikov



 •  0 comments  •  flag
Share on Twitter
Published on March 13, 2012 16:44

March 7, 2012

In defense of localStorage

Earlier this week, Chris Heilmann wrote a blog post entitled, There is no simple solution for localStorage[1] in which he decried localStorage as slow and encouraged everyone to stop using it. Surprisingly, in a post about performance, there was no mention of what "slow" or "terrible performance" actually meant. Performance can't be discussed in a vacuum, which is part of what made my reaction to his post one of confusion more than anything else.


What is slow?

So does localStorage have a performance problem? Quite simply, I don't know. Is storing and retrieving data from localStorage slower than that of a regular, in-memory object? Yes. I wrote a post about this for 2011 Performance advent calendar[2]. In fact, it's quite a bit slower when reading data out. My conclusion was that you should try to limit reads by storing multiple pieces of data in the same key. But as with most performance metrics, this really only matters when you're performing the same operation multiple times in a row. If you're only ever reading one value or writing one value, you'll likely never run into a performance issue regardless of the data size or what's going on with your system.


So localStorage is slower than using an in-memory object. Cars are slower than airplanes. What does that tell us? Not a whole lot.


Pain points

The fact of the matter is that localStorage reads from and writes to disk, which is always slower than an in-memory operation because there's hardware involved. That's the first problem. The second problem is the per-origin nature of localStorage. This characteristic means that two browser windows or tabs open to the same origin can both be reading from or writing to the same localStorage at the same time. That, in turn, means the browser needs to be incredibly smart about how it performs each operation. If tab A is writing to localStorage around the same time that tab B is reading from localStorage, which operation should happen first?


Each operation, read and write, then needs to lock localStorage to ensure data integrity. This is actually a big issue. Interacting with files is also dicey since another system process might also be working the same file. Consider a simple write operation:


localStorage.setItem("foo", "bar");

This operation is synchronous, meaning that the UI thread is blocked in the browser until the write is complete. No further JavaScript will execute and no further UI updates drawn. During this one method call, several things happen:



If localStorage is busy with another window or tab, then wait. This is problematic since there's no way to know how long this will be.
If the file is busy, then wait. The files may be scanned by antivirus, be included in a backup job, etc., and may therefore be unavailable until such operations complete. This is also problematic because it's unpredictable.
Open the file for writing.
Seek the right spot to write to the file.
Write to the file.
Close the file.

Only after all of that completes can the browser continue on to execute other statements. So really, the issue isn't that localStorage is slow, it's that localStorage must necessarily block on each operation to maintain data integrity.


Compared to cookies

The closest comparable API for JavaScript is the cookie API (though calling document.cookie an API is incredibly generous). Cookies are also name-value pairs, albeit with some additional metadata, which uses files as storage and must be synchronized across browser windows and tabs. I was surprised that Chris didn't compare localStorage to cookies since the API was clearly meant to move us from storing client-only data in cookies to storing it in localStorage. It's no accident that the localStorage API looks a lot like various cookie APIs.


When I created a benchmark[3] to test localStorage against cookies for reading and writing, the results were quite interesting. Internet Explorer, Chrome, and Safari (including iOS), reading cookies was slower than reading from  localStorage and writing to cookies was much slower than writing to localStorage. Firefox and Opera exhibit the same performance characteristics on writes as the others (with cookies being slower), but reading from a cookie is faster. So in many cases across browsers, localStorage is actually a performance improvement over using cookies with JavaScript.


APIs

The reason localStorage is popular is partly due to its simplicity. That simplicity is by design and was first designed and implemented by browser vendors, which is why it seems strange that a browser vendor would now lead the charge against an API it had a hand in creating. Yes, humans create browsers and humans can make mistakes, but I don't the design of localStorage is a mistake.


As I was reading over Chris' plea to look for alternatives, my engineer brain kept repeating to myself, "this is an implementation issue, not an interface issue". Firefox is choosing to preload the localStorage data to improve read performance later, but that's an implementation issue. Likewise, the need to read and write synchronously is an implementation issue – many forget that Internet Explorer 8′s implementation of localStorage actually wrote asynchronously. That an implementation-specific detail. Why not make all writes happen asynchronously and just keep a copy of the data in memory so it can always be read correctly regardless of the write state?


I'm not saying that this is necessarily an easy problem to solve; what I am saying is that the API design works well for developers, and for that reason it's worth looking at the implementation details to figure out if there's an efficient way to hide the warts of the system from web developers.


The proposed alternative, IndexedDB, is perhaps one of the worst API designs I've ever seen. To read and write a single piece of data requires way too many lines of code, ensuring that the API won't be used by most developers until someone comes up with a library to abstract away the horribleness. I understand the rationale behind providing such a low-level, asynchronous API (I was even part of the discussions held at Mozilla around web databases), but this absolutely stinks of browser developers creating an API that's easy to implement rather than creating an API that's easy to consume. This is the opposite of how good APIs are made. IndexedDB will never be a replacement for localStorage, it's just too complicated for most uses.


Non-blocking localStorage

As discussed previously, the real issue is that localStorage blocks on reads and writes, and the amount of time it blocks can't be determined ahead of time. If this turns out to be a concern for you (after benchmarking, of course), then the solution is to use a non-blocking  localStorage mechanism. When you hear the term "non-blocking" these days, you should immediately be thinking about Web Workers.


In the near future, I believe that client-side architectures that perform I/O should perform all of that I/O in Web Workers. That means all of your localStorage, XMLHttpRequest, Web Socket, etc., I/O should be done inside of a worker. Basically, you should be able to do something like this:


var worker = new Worker("io.js"); worker.postMessage({ type: "write", src: "localStorage", key: "foo", value: "bar" }); worker.postMessage({ type: "read", src: "localStorage", key: "foo" }); worker.onmessage = function(event) { alert(event.data.value); };

All of the reading and writing would be done off of the UI thread, so blocking really doesn't matter. I know I'm not alone in thinking this is the way of the future as the IndexedDB spec has a whole section on synchronous APIs available in workers[5]. Having synchronous APIs for IndexedDB makes it less horrible to deal with, but you need to use them in a worker. This hasn't been implemented by all browsers yet, but should be coming soon.


Workers currently have access to XMLHttpRequest, Web Sockets, File Readers, and the such…and yet no access to localStorage. Why? This is really the solution to the problem: don't throw away a great API because in some cases it will cause issues. Instead, make it available in workers so that we have an option for moving the reading/writing off of the UI thread.


Note: It's possible that the cross-domain localStorage approach I wrote about previously[6] might provide some non-blocking benefits. The cross-frame postMessage() API is asynchronous, but I've not figured out a good way to test if the containing page freezes if an iframe from the same domain accesses localStorage .


Conclusion

Asking web developers to give up localStorage is ridiculous. Are there problems with the API? Yes, indeed there are. Are they bad enough to abandon using it altogether? Absolutely not. Claims of terrible performance haven't been substantiated. Despite the complaints of browser developers as to the technical difficulties, there are no good alternatives to localStorage. We could always go back to using cookies, but as the previous benchmark shows, that doesn't necessarily guarantee better performance. And IndexedDB is a non-starter because the API is too complex for most use cases.


So to Mozilla, and the other browser vendors out there, you're a victim of your own success. You wanted to create an API that could be used in place of cookies for storing client-side data, and you created something great. The interface is friendly to web developers and that's why it's had such rapid adoption. You're all quite smart, capable people and I'm sure you can come up with better ways to implement the API than what we have today. And also, make localStorage accessible in Web Workers, please.


References

There is no simple solution for localStorage by Chris Heilmann
localStorage Read Performance by Nicholas C. Zakas
localStorage vs. cookies by Nicholas C. Zakas
Introduction to Web Storage by MSDN
Indexed Database – Synchronous APIs
Learning from XAuth: Cross-Domain localStorage by Nicholas C. Zakas



 •  1 comment  •  flag
Share on Twitter
Published on March 07, 2012 19:01

February 22, 2012

Understanding technical debt

In the creation of a web site, there are several groups of people who participate: product managers or marketing representatives who are responsible for defining functionality and design, user interface designers who create the actual visuals, and the developers who are responsible for implementing the final product. Of these groups, developers tend to get a reputation for being a bit touchy and grumpy for coming up with reasons why things can't or shouldn't be done. The reason why this happens is because the developer is, consciously or subconsciously, trying to manage the project's technical debt.


Technical debt, or tech debt for short, is quite simply the amount of technical work remaining on a project. It's something that is hard to quantify, typically existing in one or more developer minds at any given point in time. There's the initial debt of hours or days to completion which is usually the estimate delivered to the manager. After that, every technical decision that's made comes with some sort of tech debt.


Deadlines rarely align with the amount of time needed to complete work, and so technical compromises are made along the way. There's a short-term tradeoff to get something working initially. The developer knows the lifetime of the solution and accepts that he or she will have to go back and create the longer-term solution later on. While those looking in from the outside might consider this to be sloppy engineering, it's actually what allows products to be released on time. And also how tech debt accumulates.


Tech debt doesn't show up on any product roadmap and so developers frequently try to address it as they're working on other features. In some organizations, a savvy manager may be able to buy the developers some time pay down their tech debt, but that is the exception more than the rule. Those making business decisions typically don't like giving time for paying tech debt because, in their mind, the work isn't resulting in any new features. Why should they give you time to work on something when the end result isn't a new feature?


In the worst case, tech debt can accumulate to the point where the web application is destined to fail. A classic tech debt issue is scalability. Initially, the goal is to get the web application up and running so that anyone can use it. Decisions are made to allow that to happen. But an app that can handle 100 users isn't built the same way as an app to handle 1,000,000 users. In the back of the developers' minds are a list of things that need to happen in order to scale out: hit the database less, implementing several layers of caching, reduce the size of responses, figure out a faster way to process orders, and so on.


Just like monetary debt, tech debt is best dealt with before it gets too large and overwhelming. Regularly tending to tech debt is a process I like to call code hygiene. If you don't go to the dentist for ten years and then finally go, chances are you'll be in for a nasty surprise by not practicing proper dental hygiene. Code hygiene is the same. Keeping on top of your tech debt means regularly going in and addressing what you can with the time available. Good code hygiene means regularly:



Deleting unused code – I always say that any day you can delete multiple lines of code is a good day, and one where you earned your paycheck. Unused code shouldn't be allowed to live in a codebase because, just like bacteria, all it needs is one opening to cause a big problem. If you suspect code isn't being used, verify and then remove it. Don't make a note to do it later, thus creating more tech debt, do it immediately. Less code means less to go wrong and faster builds and deployments.
Refactor code – The time to refactor is as soon as you notice a problem. Don't allow sloppy or bad code to remain in the code base. Code has a way of duplicating itself without warning. New developers come in looking for an example, find bad code, copy it, and now you have two pieces of bad code instead of one. That's more tech debt. Make sure that all code you check in is worthy of being copied to prevent future tech debt. When you're building off of existing code, make sure to include some time in your estimates for refactoring.
Rewrite code – It's rare for developers to be able to rewrite something from scratch, but it's a necessary part of code hygiene. Good code should be able to run for five years without being rewritten; bad code needs to be rewritten as soon as possible. You should always try to refactor first, but if that fails, it's time to rewrite. Making the business case for rewriting is difficult, but if you can tie the rewrite to a new feature, you have a better chance of getting the time.

Technical debt is a part of every project, and one that needs to be better understood by all parties involved. Building time into every release for code hygiene is a good idea and can take many forms: bug bashes, where everyone takes a day or two and just works on bugs, engineering-driven features, which are features of the platform rather than end-user features, and code reviews, where engineers inspect each other's code, are all good practices to have on the team to ensure tech debt doesn't get out of control.




 •  0 comments  •  flag
Share on Twitter
Published on February 22, 2012 09:13

February 13, 2012

Book review: The Art of Readable Code

The Art of Readable Code Book CoverWhen I first proposed my upcoming book, Maintainable JavaScript, I was offered the chance to review a book on a similar topic. The Art of Readable Code by Dustin Boswell and Trevor Foucher is a book after my own heart. While not strictly about JavaScript, this book delves into the little explored region of code hygiene like no other. I'm a big believer in the value of readable, maintainable code, and this book presents some great techniques for overall code readability regardless of language.


The book starts by talking about time until understanding, and how important that is for programmer productivity.Of course, you can't even begin to start working with code until you understand it. The authors talk about just how important this is on a large development team where you have multiple people working on the same code at different times in the project. This is something I've been preaching for a while in my talks, and I'm glad that The Art of Readable Code follows the same reasoning.


The first few chapters go into specifics of naming and how naming can really help in the understanding of code. Little tidbits about how naming affects our understanding are included, as well as some of the questions around naming such as how long the name should be. The difference between a naming variables, functions, and Constance is discussed, along with some great examples of how to naming should meet developer expectations. For example, a method beginning with the word "get" this often assumed to be a fast getter method that doesn't do much processing. However, if such a method ends up doing expensive processing and taking a long time, this gets confusing for developers. I had never thought about method naming in this way, but it makes a lot of sense.


The next few chapters focus on comments and when to use them. This is another topic that's very close to my heart, as I generally feel like people don't use comments enough. These chapters have some great examples of both bad and good comments. If we all just commented a little more, dealing with the world's code would be much easier.


Other topics in the book include how to properly structure flow control statements for best understanding, how to properly break down large chunks of code, and how to re-factor for better readability. Most of the topics are accompanied by small comics that help to get the point across and give some welcome levity to the discussion.


If you care about writing maintainable code, whether it be in JavaScript or any other language, this book is a great read. Those who never stopped to consider how their coding style affects the maintainability of their code should definitely pick up this book to get a nice overview of the issues. Every reader will appreciate how the authors continually say that there is no one right way to do anything, it's all based on the context of your code and your team. I found myself disagreeing with some of the approaches in the book, but with a complete understanding of why the authors would choose that particular approach. But that's okay, as it shows an important concept in maintainable code: it's much more important for everyone to be doing things one way than it is for everyone to be doing things your way.




 •  0 comments  •  flag
Share on Twitter
Published on February 13, 2012 13:54

January 19, 2012

CSS media queries in JavaScript, Part 2

In my previous post[1], I introduced using CSS media queries in JavaScript both through a custom implementation and using the CSSOM Views matchMedia() method. Media queries are incredibly useful, both in CSS and JavaScript, and so I continued with my research to see how best to take advantage of this capability. As it turns out, the matchMedia() method has a few interesting quirks that I didn't realize when I wrote the first part of this series.


matchMedia() and its quirks

Recall that matchMedia() returns a MediaQueryList object that allows you to determine whether or not the given media type matches the current state of the browser. This is done using the matches property, which returns a boolean. As it turns out, matches is a getter, which requeries the state of the browser each time it's called:


var mql = window.matchMedia("screen and (max-width:600px)");
console.log(mql.matches);

//resize the browser

console.log(mql.matches); //requeries

This is actually really useful, because it allows you to keep a reference to a MediaQueryList object and repeatedly check the state of the query against the page.


Chrome and Safari have a weird behavior, though. The initial value for matches is always correct but doesn't get updated by default unless the page has a media block defined with the same query and at least one rule (hat tip: Rob Flaherty[2]. For instance, in order for a MediaQueryList representing "screen and (max-width:600px)" to update appropriately (including firing events), you must have something like this in your CSS:


@media screen and (max-width:600px) {
.foo { }
}

There needs to be at least one rule in the media block, but it doesn't matter if that rule is empty. As long as this exists on the page then the MediaQueryList will be updated appropriately and any listeners added via addListener() will fire when appropriate. Without this media block on the page, the MediaQueryList acts like a snapshot of the page state at its creation time.[3]


You can fix this by adding a new rule using JavaScript:


var style = document.createElement("style");
style.appendChild(document.createTextNode("@media screen and (max-width:600px) { .foo {} }"));
document.head.appendChild(style); //WebKit supports document.head

Of course, you would need to do that for every media query being accessed using matchMedia(), which is a bit of a pain.


There is also a strange quirk in Firefox's implementation. In theory, you should be able to assign a handler for when the query state changes and not keep a reference to the MediaQueryList object, such as:


//doesn't quite work in Firefox
window.matchMedia("screen and (max-width:600px)").addListener(function(mql) {
console.log("Changed!");
});

When this pattern is used in Firefox, the listener may never actually be called even though the media query has become valid. In my tests, it would fire between 0 and 3 times, and then never again. The Firefox team has acknowledged this is a bug[4] and should hopefully be fixed soon. In the meantime, you need to keep the MediaQueryList reference around to ensure your listeners fire:


//fix for Firefox
var mql = window.matchMedia("screen and (max-width:600px)");
mql.addListener(function(mql) {
console.log("Changed!");
});

The listener here will continue to be called as long as there is a reference to the mql object.


More on listeners

My initial description of the media query listeners in my previous post was incomplete due to a misunderstanding on my part. The listeners are actually trigger in two instances:



When the media query initially becomes valid. So in the previous example, when the screen becomes 600 pixels wide or less.
When the media query initially becomes invalid. For example, when the screen becomes wider than 600 pixels.

This behavior is why the MediaQueryList object is passed into the listener, so you can check matches to determine if the media query just became valid or not. For example:


mql.addListener(function(mql) {
if (mql.matches) {
console.log("Matches now!");
} else {
console.log("Doesn't match now!");
}
});

Using code like this, you can monitor when a web application moves into and out of certain states, allowing you to alter the behavior accordingly.


To polyfill or not?

When I first looked at matchMedia(), I did so with the intent of creating a polyfill. Paul Irish[5] implemented a polyfill using a technique similar to the one I described in my last post (and gave me credit for it, thanks Paul!). Paul Hayes then forked[6] his work to create a polyfill with rudimentary listener support based on a very ingenuous use of CSS transitions to detect changes. However, as it relies on CSS transitions, the listener support is limited to browsers with CSS transition support. That, coupled with the fact that calling matches doesn't requery the browser state, and the bugs in both Firefox and WebKit, led me to believe that building a polyfill wasn't the right approach. After all, how can you polyfill appropriately when there are such obvious bugs in the real implementations that need fixing?


My approach was to create a facade to wrap this behavior in an API where I could smooth out the issues. Of course, I chose to implement the API as a YUI Gallery module[7] called gallery-media. The API is very simple and consists of two methods. The first is Y.Media.matches(), which takes a media query string and returns true if the media matches and false if not. No need to keep track of any objects, just get the info:


var matches = Y.Media.matches("screen and (max-width:600px)");

The second method is Y.Media.on(), which allows you to specify a media query and a listener to call when the media query becomes valid or invalid. The listener is passed an object with matches and media properties to give you information about the media query. For example:


var handle = Y.Media.on("screen and (max-width:600px)", function(mq) {
console.log(mq.media + ":" + mq.matches);
});

//detach later
handle.detach();

Instead of using CSS transitions to monitor for changes, I use a simple onresize event handler. On the desktop, the size of the browser window is the main thing that will change (as opposed to mobile devices, where the orientation may also change), so I made this simplifying assumption for older browsers. The API uses the native matchMedia() functionality where available and patches up the differences in WebKit and Chrome so that you get consistent behavior.


Conclusion

CSS media queries in JavaScript are a bit more complicated than I first expected, but still quite useful. I don't think it's appropriate to polyfill matchMedia() giving the strange bugs that are still abound, effectively preventing you from even using the native code the same way across browsers. A facade, on the other hand, insulates you from the bugs and changes that are likely to occur going forward. Now go forth and use CSS media queries to their potential…in JavaScript.


References

CSS media queries in JavaScript, Part 1 by me
Rob Flaherty's tweet

matchMedia() MediaQueryList not updating
matchMedia() listeners lost
matchMedia polyfill by Paul Irish
matchMedia polyfill by Paul Hayes
YUI 3 Gallery Media module by me



 •  0 comments  •  flag
Share on Twitter
Published on January 19, 2012 07:30

January 17, 2012

Book review: The Tangled Web

The Tangled WebI'm not really sure what I was expecting from The Tangled Web: A Guide to Securing Modern Web Applications. Having learned more about web security in the past year, I suppose I was hoping for a more in-depth treatment of common web application security issues. In my mind, I pictured a chapter on Cross-Site Scripting attacks and mitigation steps, a chapter on Cross-Site Request Forgery and what to do about it, etc. Instead, the book tackles the security problem with an exhaustive and dry examination of all the technologies that make up the web. Though interesting technically, it's very easy to get lost in these details and end up at the other end unsure of how the description relates to real-world security issues.


For instance, the author goes into how a URL is parsed and the differences between how different browsers parse URLs. That's interesting information, but I'm still not sure what type of attacks I should look out due to these issues and how to address them if they do occur. The same treatments are given to HTTP itself, HTML, CSS, JavaScript, and other parts of web application stack.


One of the most frustrating aspects of this book is how browser names are frequently thrown around without version numbers. Saying "Internet Explorer" does something leaves me wondering if that was one of the many issues fixed in Internet Explorer 9 and 10 or not. While it's fine to leave off version numbers when discussing Chrome, Internet Explorer just has far too many differences to make this useful.


I found the code examples to be incredibly terse, and in some cases missing completely. Case in point, a discussion of the sandbox attribute for doesn't have a single code example showing its proper usage. Certainly property usage is part of ensuring security. Other sections of the book suffer from the same code-terseness to its detriment. A lot of the topics could stand more actual examples.


Which brings me to my overall issue with the book: it reads more like it was written by a researcher for a researcher. This really isn't a book to help you solidify your web application security. In fact, I'm not sure I picked up any new techniques from reading the book at all. My head is now filled with trivia knowledge about web browsers that I'm unable to practically apply to my work, which is frustrating. The only attempt the author makes at giving actionable advice is on the "checklist" at the end of each chapter. The checklist contains way-too-terse descriptions of how to mitigate certain attacks…but without practical code examples, the bullet points are quite lost.


This book seems mostly targeted at amateur security professional who need a good brain dump on all the various flaws in internet protocols and technologies in order to get their feet wet. It's definitely not for web developers looking to improve their web application security, making the subtitle, "A Guide to Securing Modern Web Applications", a complete misnomer. If anything, it's a guide through current web technologies showing you that the internet is a mess and leaving you to wonder how to fix it.


I really, really wanted to like this book, but unfortunately, I just didn't find it practical enough to recommend it as guide for most web developers. If you don't understand security issues at all, then this is probably a good book to pick up, but otherwise, you'll need to go elsewhere to find practical advice.




 •  0 comments  •  flag
Share on Twitter
Published on January 17, 2012 07:30

January 9, 2012

Now available: Professional JavaScript, 3rd Edition

Professional JavaScript, 3rd EditionI'm very excited to announce that Professional JavaScript for Web Developers, 3rd Edition is now shipping and available in bookstores. Over six years, the first edition was released and it changed my life in ways I never could have anticipated. It was through this book that I ended up at Yahoo! and was invited to speak at conferences for the first time. The first edition was a labor of love and that love has continued over the years through the second edition and into this one, which took over a year to complete.


Those who know me shouldn't be surprised that this book is more than just an update. The 3rd edition features five completely new chapters covering the new HTML5 APIs such as history state managements, canvas, offline applications, web workers, and more. Throughout the book, I've added references to changes in ECMAScript 5, including how strict mode works and how to use the new object-creation APIs. All of the existing chapters were also updated with the latest browser support information including mobile support (sadly, that will always be a bit out-of-date). A special appendix about ECMAScript Harmony is also included to give you a taste of the future.


I'm also incredibly honored to have a foreword written by Rey Bango. Rey had so many kind words about the 2nd edition that I was thrilled when he agreed to write the foreword for this one. And here it is:


I look back at my career (now 20+ years) and in between coming to the realization that my grey hairs

have really sprouted out, I reflect on the technologies and people that have dramatically affected

my professional life and decisions. If I had to choose one technology, though, that has had the single

biggest positive influence on me, it would be JavaScript. Mind you, I wasn't always a JavaScript believer.

Like many, I looked at it as a play language relegated to doing rotating banners and sprinkling some

interesting effects on pages. I was a server-side developer and we didn't play with toy languages, damn

it! But then something happened: Ajax.


I'll never forget hearing the buzzword "Ajax" all over the place and thinking that it was some very cool,

new and innovative technology. I had to check it out and as I read about it, I was floored when I realized

that the toy language I had so readily dismissed was now the technology that was on the lips of every

professional web developer. And suddenly, my perception changed. As I continued to explore past what

Ajax was, I realized that JavaScript was incredibly powerful and I wanted in on all the goodness it had to

offer. So I embraced it wholeheartedly working to understand the language, joining the jQuery project

team and focusing on client-side development. Life was good.


The deeper I became involved in JavaScript, the more developers I met, some whom to this day I still

see as rockstars and mentors. Nicholas Zakas is one of those developers. I remember reading the second edition of this very book and feeling like, despite all of my years of tinkering, I had learned so much.

And the book felt genuine and thoughtful, as if Nicholas understood that his audience's experience

level would vary and that he needed to manage the tone accordingly. That really stood out in terms of

technical books. Most authors try to go into the deep-dive techno-babble to impress. This was different

and it immediately became my go-to book and the one I recommended to any developer that wanted

to get a solid understanding of JavaScript. I wanted everyone to feel the same way I felt and realize how

valuable a resource it is.


And then, at a jQuery conference, I had the amazing fortune of actually meeting Nicholas in person.

Here was one of top JavaScript developers in the world working on one of the most important web

properties in the world (Yahoo!) and he was one of the nicest people I had ever met. I admit, I was a bit

starstruck when I met him and the great thing is that he was just this incredibly down-to-earth person

who just wanted to help developers be great. So not only did his book change the way I thought about

JavaScript, Nicholas himself was someone that I wanted to continue to work with and get to know.


When Nicholas asked me to write this foreword, I can't explain how flattered I was. Here I am being the

opening act for the guru. It's a testament to how cool of a person he is. Most importantly though, it

gives me an opportunity to share with you why I felt this book is so important. I've read many JavaScript

books and there are certainly awesome titles out there. This book, though, offers in my opinion the total

package to make you an incredibly proficient and able JavaScript developer. The smooth and thoughtful

transition from introductory topics such as expressions and variable declarations to advanced topics

such as closures and object-oriented development is what sets it apart from other books that are either

too introductory or expect that you're already building missile guidance systems with JavaScript. It's

the "every man's" book that will help you write code that you'll be proud of and build websites that will

excite and delight.


Rey Bango

Sr. Technical Evanglist, Microsoft Corporation

jQuery Project Team


I hope that Rey, and all of you, enjoy the 3rd edition just as much as (if not more than) the 2nd edition. The book is available for purchase at Amazon and available for download as an ebook from Wrox.




 •  0 comments  •  flag
Share on Twitter
Published on January 09, 2012 11:48

January 5, 2012

CSS Lint v0.9.2 now available

A new version of CSS Lint is now available both on csslint.net and through npm for NodeJS. Version 0.9.2 focused on improving validation support (full support is planned for v1.0.0) and stability. As part of that, 0.9.1 and 0.9.2 were quickly rolled out after 0.9.0 to address some flaws in the validation logic.


Other changes for this release:



Dino Chiesa submitted a Windows Script Host (WSH) CLI.
There were a couple of parser compatibility bugs that were fixed.
Various rules regarding vendor prefixed properties were updated to reflect Internet Explorer 10.
New Rule: The fallback-colors rule was suggested by Dustin Cass and warns when a CSS3 color is used without a CSS2 fallback (rule documentation)
New Rule: The duplicate-background-images was created by Hans-Peter Buniat and warns when a background image is used more than once ((rule documentation)

Thanks once again to the CSS Lint community for continuing to file bugs and make feature requests. We're rapidly approaching and very stable v1.0.0 release due to your participation and feedback. Keep it coming!




 •  0 comments  •  flag
Share on Twitter
Published on January 05, 2012 09:42

January 4, 2012

Proposal: Scripting detection using CSS media queries

I've been doing a lot of thinking about CSS media queries lately. I'm a big fan of media queries, as I think they bring a sense of sanity to feature detection. That's a big reason why I was investigating CSS media queries in JavaScript[1] and will continue to do so. I think we're only scraping the surface of what can be done with media queries on the web. As part of my pondering over the holiday break, I scribbled down a few notes of ways I'd like to use media queries. I just proposed the first one to the CSS working group.


The Proposal

Yesterday, I sent an email[2] to the CSS working group with my proposal. The basic idea is to allow you to determine if scripting is enabled in the browser using a media query. The proposal can be summed up with a few examples:


@media screen and (script) {
/* styles to apply only when scripting is enabled */
}

@media screen and not (script) {
/* styles to apply only when scripting is disabled */
}

So, just like you currently use device-width, orientation, and so on to detect features of the device, you could also use script in the same way.


Rationale

In the realm of progressive enhancement, you don't want to show page elements that can't be used. This may be as simple as an arrow next to link indicating a dropdown menu is available. If JavaScript is disabled, you want the link to act like a regular link and not confuse people by having an arrow that means nothing. So you want to apply the style that shows the arrow only if JavaScript is enabled.


The most common approach to this problem is to add a class to the element via JavaScript. So somewhere on the page, you put:



This adds the class js-enabled via JavaScript. Of course, this only gets executed when JavaScript is enabled. You can then define CSS rules such as:


.arrow {
/* empty */
}

.js-enabled .arrow {
background: url(image.png) no-repeat;
}

It's a bit of a hack, but this basic technique is in use by large sites such Twitter and the Yahoo! homepage, as well as being done automatically by Modernizr and YUI.


While this technique works, it has two downsides. First, you need to include that little JavaScript snippet (or a supporting library) to ensure the class ends up being added. Second, it alters the specificity of your rules, which can adversely affects the cascade.


Clarifications

I'm a big believer that common patterns should be codified and standardized so that the development community can move on to more interesting challenges[3]. As such, it seems that the community has spoken that we want to define different styles when JavaScript is enabled, and CSS media queries seem like the right approach.


The CSS Media Queries specification[4] states:


A media query consists of a media type and zero or more expressions that check for the conditions of particular media features. Among the media features that can be used in media queries are 'width', 'height', and 'color'. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself.


The term media feature is key. When I was first debating myself over whether scripting support is appropriate for a CSS media query, I went and read the specification. Script support is just as much a media feature as color depth and orientation. It's a capability of that particular device at the time your page is loaded. Given that, I felt comfortable proposing the inclusion of script as another media feature to test.


To be clear, my proposal's goal is to easily indicate whether or not scripting is enabled in a browser. Think of it as a relative of the element. So instead of doing something like this:




.foo {
color: red;
}


You could do this:


@media screen and not (script) {
.foo {
color: red;
}
}

Of course, by omitting not, you could also apply changes when scripting is enabled.


Some non-goals of this proposal are:



Replacing JavaScript feature detection. You will still be checking, in JavaScript, if certain features are available. In short: I'm not looking to propose implementing media query features for all possible JavaScript APIs. If you want that, you should use Modernizr.
Enabling JavaScript in CSS. I have no desire to have JavaScript in CSS in any way, shape, or form.
Be JavaScript-centric in detection. Actually, the intent is to indicate if scripting is enabled, not just JavaScript. It would probably be easy to extend the syntax, such as (script:"text/javascript"), but I'm not sure that's necessary at this point.

And as I always like to remind people: no one would force you to use this feature if it's implemented. If you don't like it, you can always leave it to those who do.


Conclusion

I think CSS media queries are one of the best things to happen to the web, and I look forward to using them in new and interesting ways. Adding feature detection for scripting seems like a logic step towards standardizing a fairly common practice. The good news is that Florian Rivoal, one of the editors of the CSS Media Queries specification has agreed[5] to write it up as a proposal for inclusion in CSS Level 4 Media Queries. I hope the proposal is able to move forward quickly.


References

CSS media queries in JavaScript, Part 1 by me
Proposal: Detecting JavaScript with media queries by me
When web standards fail us by me
CSS Level 3 Media Queries
Re: Proposal: Detecting JavaScript with media queries by Florian Rivoal



 •  0 comments  •  flag
Share on Twitter
Published on January 04, 2012 10:41

January 3, 2012

CSS media queries in JavaScript, Part 1

Early in 2011, I was working on a project where I was doing some feature detection in JavaScript. Some tinkering led to the thought that using a CSS media query would work much better and so I spent some time coming up with a function to use CSS media queries in JavaScript. My thought process was simple: if I'm only applying certain CSS based on a media query, I also only want to run certain JavaScript based on a media query. The result was the following function, which I first published as a Gist[1] last March:


var isMedia = (function(){

var div;

return function(query){

//if the
doesn't exist, create it and make sure it's hidden
if (!div){
div = document.createElement("div");
div.id = "ncz1";
div.style.cssText = "position:absolute;top:-1000px";
document.body.insertBefore(div, document.body.firstChild);
}

div.innerHTML = "_



The idea behind this function is pretty simple. I create a node with a media attribute equal to the one I'm testing. Inside, there's a CSS rule applied to a and all I have to do is check to see if the style has been applied. I wanted to avoid browser detection, so instead of using currentStyle and getComputedStyle(), I decided to just change the width of an element and check it using offsetWidth.


Very quickly, I had a version of this function that worked in almost all browsers. The exceptions, as you may have guessed, were Internet Explorer 6 and 7. In those browsers, the element is considered a NoScope element[2]. NoScope elements were a horrid exception to what happens when HTML is injected into a page using innerHTML or any other means. All NoScope elements are effectively dropped if they are the first element added as an HTML string. In order to use a NoScope element, you must be sure that it's not the first part of an HTML string. Thus, I put the underscore in before the element and then remove it – tricking Internet Explorer 6 and 7 into applying the element as it should. Other browsers don't have this NoScope element issue, but using this technique doesn't negatively effect them (as I said before, I was trying to avoid browser detection).


In the end, you can use the function like this:


if (isMedia("screen and (max-width:800px)"){
//do something for the screen
}

if (isMedia("all and (orientation:portrait)")){
//react to portrait mode
}

The isMedia() worked great in all browsers I tested (back to Internet Explorer 6) in that it accurately detects whether the browser thinks the media query is valid. So passing in an unsupported query to any browser always returns false. Internet Explorer 6, for instance, returns true if you use "screen", but anything more complex and it returns false. I thought this was acceptable because any CSS in other media queries wouldn't be applied in that browser anyway.


CSSOM View

matchMedia(), to the window object. You pass in a CSS media query and receive back a MediaQueryList object. The object contains two properties: matches, which is a boolean value indicating if the CSS media query matches the current view state, and media, which is the same string that was passed in. For example:


var match = window.matchMedia("screen and (max-width:800px)");
console.log(match.media); //"screen and (max-width:800px)"
console.log(match.matches); //true or false

So far, this API doesn't provide much more than my Gist. You may be wondering, though, why does matchMedia() return an object? After all, if the media doesn't match, of what use is it? The answer is in two methods: addListener() and removeListener().


These two methods allow you to interact with view state changes based on CSS media queries. For instance, maybe you want to be alerted when a tablet is switched to portrait mode. You could do something like this:


var match = window.matchMedia("(orientation:portrait)");
match.addListener(function(match){
if (match.media == "(orientation:portrait)") {
//do something
}
});

This code adds a listener for a media query. When the query becomes true for the current view state, the listener is executed and the corresponding MediaQueryList object is passed in. In this way, you can have your JavaScript be just as responsive as your layout without polling. So unlike my Gist, this API allows you to monitor the changing view state and adapt the interface behavior accordingly.


The matchMedia() method is available in Chrome, Safari 5.1+, Firefox 9+, and Safari for iOS 5+. These represent the browsers that I have access to and can verify. Internet Explorer and Opera still don't support matchMedia() as of their latest versions.


Conclusion

CSS media queries bring a simple feature detection syntax to both CSS and JavaScript. I expect that media queries will become a big part of JavaScript coding in the future, alerting developers as to when significant interface changes occur. There is no reason that the behavior of a web application shouldn't be just as responsive as the layout, and CSS media queries give us that power today.


References

A function for detecting if the browser is in a given media mode
MSDN: innerHTML Property
CSS Object Model View



 •  0 comments  •  flag
Share on Twitter
Published on January 03, 2012 07:30

Nicholas C. Zakas's Blog

Nicholas C. Zakas
Nicholas C. Zakas isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Nicholas C. Zakas's blog with rss.