JavaScript: Condensed Code vs. Readability
I've been coding some more advanced JavaScript applications lately and they've made me think a lot about coding styles. More specifically: shortness of code vs. readability.
My Mindset
I can be a conflicted developer sometimes, so here are a few thoughts that go through my mind:
- "Tools like the YUI Compressor will compress my code enough."
- "Sure YUI Compressor will shorten the code but it wont address shortening strings as arguments."
- "With broadband internet, a few KB really wont matter."
- "With mobile bandwidth constraints, I need this JS file to be as tiny as possible."
- "I want this app to be easy enough for me to step into and understand again within 5 minutes."
- "I want to be able to reuse some of this code in future projects without a bunch of hassle."
- "How easy is it to judge 500 feet? If I stay a reasonable distance away from Christina Ricci, can they definitively prove I broke the restraining order?"
A Quick and Easy Example
Take the following verbose code snippet for example:
myElement.addEvent('click',function() { var parent = myElement.getParent(); parent.setStyle('border','1px solid #f00'); var tag = parent.get('tag'); if(tag == 'a') { myElement.setStyle('display','none'); } else { myElement.setStyle('display','block'); } parent.tween('opacity',1); });
Though the snippet is very readable, it can be shortened quite a bit:
myElement.addEvent('click',function() { var parent = myElement.getParent().setStyle('border','1px solid #f00').tween('opacity',1); myElement.setStyle('display',parent.get('tag') == 'a' ? 'none' : 'block'); });
The above case shows a sacrifice of readability for the sake of short code. It would be easy to gloss over the "setStyle" added to the parent. All things considered, which is better for you?
The String Concern
String literals aren't addressed by the YUI Compressor. So the following snippet...
//more above... myElement.addEvent('click',function() { var halfOpacity = 0.5, fullOpacity = 1; if(myElement.hasClass('opacity')) { myElement.setStyle('display',halfOpacity).set('text','Can you see me?'); } else { myElement.setStyle('display',fullOpacity).set('text','You cannot miss me!'); } }); //more below....
...becomes...
myElement.addEvent("click",function(){var b=0.5,a=1;if(myElement.hasClass("opacity")){myElement.setStyle("display",b).set("text","Can you see me?")}else{myElement.setStyle("display",a).set("text","You cannot miss me!")}});
Even though the "display" and "text" strings are used twice, they aren't shortened/replaced by a variable. Since we're foregoing readability by using the YUI compressor and only desire to have the shortest code possible, I feel like the above is a major fail.
The String Compromise
When extreme shortness of code with readability is important, I'll take string literals and create variables with their same name at the very top of my application. Doing so keeps my variables readable when coding and allows YUI to really crunch the code. Here's the before:
window.addEvent('domready',function() { /** settings on top; frequently used strings **/ var _click = 'click', _opacity = 'opacity', _text = 'text'; //now do everything below //.... $(myElement).addEvent(_click,function() { var halfOpacity = 0.5, fullOpacity = 1; if(myElement.hasClass(_opacity)) { myElement.setStyle(_opacity,halfOpacity).set(_text,'Can you see me?'); } else { myElement.setStyle(_opacity,fullOpacity).set(_text,'You cannot miss me!'); } }); //.... });
..and the after...
//37% compression -- nice!! window.addEvent("domready",function(){var b="click",a="opacity",c="text";$(myElement).addEvent(b,function(){var e=0.5,d=1;if(myElement.hasClass(a)){myElement.setStyle(a,e).set(c,"Can you see me?")}else{myElement.setStyle(a,d).set(c,"You cannot miss me!")}})});
Awesome -- the code is still readable and frequently used strings can be compressed. Our code's compression ratio for this block alone becomes 37% -- a very significant number
Object Methods: Too Much?
You could stake it a step further by using Array-style syntax and variable methods to assist the YUI Compressor. The before:
window.addEvent('domready',function() { /** settings on top; frequently used strings **/ var _click = 'click', _opacity = 'opacity', _text = 'text'; var _addEvent = 'addEvent', _hasClass = 'hasClass', _setStyle = 'setStyle', _set = 'set'; //now do everything below //.... $(myElement).addEvent(_click,function() { var halfOpacity = 0.5, fullOpacity = 1; if(myElement[_hasClass](_opacity)) { myElement[_setStyle](_opacity,halfOpacity)[_set](_text,'Can you see me?'); } else { myElement[_setStyle](_opacity,fullOpacity)[_set](_text,'You cannot miss me!'); } }); //.... });
...and the after...
//47% compression! FTW! window.addEvent("domready",function(){var c="click",b="opacity",f="text";var e="addEvent",d="_hasClass",g="setStyle",a="set";$(myElement).addEvent(c,function(){var i=0.5,h=1;if(myElement[d](b)){myElement[g](b,i)[a](f,"Can you see me?")}else{myElement[g](b,h)[a](f,"You cannot miss me!")}})});
Too much? I suppose it depends on the skill lever of the coder and the desire to make the code short.
What Do You Think?
What are your thoughts on the epic battle between readability and code compression? I think it really depends on the developer but I'd love to hear your thoughts!
Personally I don’t “encode”, shorten or do anything with my code. Currently I’m working on web-based applications and as a result, I generally have 2 user interfaces, one for Mobile and the other for computer based browsers. This results in having 2 javascript files on the server. In terms of load times, my projects don’t have that much difference between encoded and ‘normal’.
Plus on the upside, it saves me time trying to translate, decode or ‘humanize’ code. :)
I think that compressors, especially google closure compiler make you write javascript differently, only exposing what’s needed.
The compressors do take care of the bandwidth issue, so for the uncompressed version, it should be as verbose as possible.
The changes that you are writing piece of code that will only be read by you are not high, might as well write it as “understandable” as possible.
Not necessarily bloated with comments, but any functions that are not in the global namespace should be named with names that are long enough to make the meaning of the function easy to comprehend..
That’s my 2 pennies!
I don’t really matter about that, I use jsmin to compress embedded js snippets http://github.com/rgrove/jsmin-php/ . so the code remains readable
for the js files I use the google minifier.
I almost choked with your Christina Ricci reference!!
I pretty much always choose readability over compression… I like to be able to understand my code few months later, and I also appreciate the fact that OTHER developers might wanna take a look under the hood…
With High speed Internet (and Unlimited Internet for the majority of mobile Internet users) I’m not minding the few additional Kb.
Which is why I leave it “readable”. But that’s just me, heh!
I prefer to keep things readable. If I’m building for a larger web application, I worry more about requests to the server than I do a few kb here and there. So my first step is to combine my script files and check improvement rather than spending time chaining function calls together.
What is your opinion on loading -min (YUI or Closure) versions of files but also keeping the full versions on the live server? We do that at work, but is it commonplace?
She’s crazy with the restraining orders, right? I mean one little obsessive I want to lick your face comment while tackling her to the ground, and she gets all huffy. *sigh* Anyway…
I completely agree with being verbose in the source files, and if I do use shortcut methods such as conditional expressions (especially those used inline), I will always add the necessary parenthesis to visually illustrate even a basic order of operation.
myElement.setStyle('display', (parent.get('tag') == 'a' ? 'none' : 'block'));
Especially on unary operators.
var restrainingOrders = ((++meToo) || 1);
I never took the time to notice YUI had no effect on string literals, but I love the solution of using indexed arrays for element methods. Beautiful solution! ^_^
Many of the advanced minification optimizations become marginal improvements once you consider HTTP compression (i.e. gzip/deflate). I prefer to keep the code readable, and not count on minification to do much more than remove whitespace and comments; basically preparing it for HTTP compression.
I put a minified version into production, but I keep a standard, readable version available for future changes. The best of both worlds.
I keep a readable file on disk, but create a compressed one and upload it to run the javascript on my pages. That way my scripting doesn’t get ripped as easily and I can still edit it.
Great article!
I prefer writing in the style of
myElement.setStyle('display',parent.get('tag') == 'a' ? 'none' : 'block');
.I use a custom parser/compressor that also caches and packs my JS or CSS code with gzip, keeping the original source clean and readable no matter if production or development. I.e., several JS or CSS-files are concatenated, parsed and cached. Reduces several HTTP requests to one. ;)
Need to look at the YUI compressor again some day soon though.
@Jacob Rask: Yes, that’s commonplace, but it doesn’t address some of my compressions issues.
Google’s Closure Compiler would shorten the method names for you when compiling your code in advanced mode:
The problem of advanced mode is that it renames even global variables, so you have to compile all your JS code at once.
Still, it does not seem to cache the string literals, even if used more than once.
I also generally prefer readability over compression. The PHP5 Minify http://code.google.com/p/minify/ does a great job for my current compressing needs.
Still I pretty much relate to this kind of obsession. Maybe you could write a pre-processor for the minifier (propably for the YUI compressor too) and use a dictionary to replace the most common literals with your “object method” notation. This way you might get higher compression ratios while keeping readability. Perhaps a couple of preg_replaces would do the trick?
With so much emphasis on reuse in our contemporary society I strongly sway on the side of readability. There is nothing worse than picking up from someone else a chunk of code and having to slog your way through it before you can use it … of course this wouldn`t happen and reuse goes out the window. There is the argument for heavily commented sort code, however we don`t always comment our code especially when deadlines are closing in on us. And when compressing we loose all comments.
I tend to go for readable code and then compress it, having two versions. This may be duplication but saves an awful lot of time.
This is a Blu-Ray, broadband era.. I agree 100% with you. Few KB will not slow down a site a bit.
Readability is important for future code manipulation.
I like the code to be understandable..
We have many minify tool which minifies code server side..without affecting the main code..
I prefer to keep my code readable to good developers only, not my boss or some junior boys.
Let’s consider this example.
It can be shortened with ES6 syntax.
You know, my boss doesn’t understand the latter one.
I prefer readability + clarity over shortness. Loading over 3G is still an issue, sadly. However, the original snippet (sans comments) gzips to 206 bytes, the final minified (47%) snippet gzips to 198 bytes.
Great discussion, BTW.