Efficiency-first Versus the Collaborative-friendly

Author Image - Steve Morland

By Steve Morland

Technical Design Lead at Leighton, Steve manages all of our development teams delivering exceptional technical platforms to our clients

What's more important; minified, more-efficient fit-for-purpose succinct code, or bloated, well-commented, readable and reusable code?

If you’re talking about back-end code then of course you don’t really care about white space and code bloat, but recently I was tasked to take some existing JavaScript that more or less worked perfectly in one application and port it to another. Sounds easy, right?

Wrong!

The code was extremely well written in terms of efficiency. So much so that without any comments it was brain-melting; trying to follow the code was painful. Not only that, but when I eventually hacked together some working code, I soon realised it wasn't flexible enough for what I was trying to do. It was written for one use case and to get it to work in my scenario required a lot of hacking which neutralised any of the existing efficiency benefits.

There is no doubt that web pages and web applications should be snappy, so keeping your code as small as possible should definitely be at the forefront of your design; laggy JavaScript can ruin a user’s experience completely. But equally, you might not be the only developer to have to work on this file or functionality and invariably when a developer doesn't understand existing code they break it, or duplicate it, or worse still, waste productive time re-writing it all!

Sadly for me, it was all of the above. I broke it, I duplicated it, and eventually I had to re-write it completely. And I took this opportunity to improve it. What did I do differently? First step, and the easiest, was simply adding comments.

Commenting code should be as important as writing the code itself. You should take pride in commenting your code – use your comments to brag about how cleverly and elegantly you've solved a problem! My comments in this case roughly doubled the size of the file, it wasn't all bragging either. When the file goes onto the production server I can of course minify it; aggressively minifying could reduce 700 lines of code to around 40 lines. The important thing about comments is that not only does it mean it’s easier for someone to understand the code but the comments can walk them through it, give them examples of parameters or explain any abstract functions and patterns. You can also explain any decisions you've made that might not be obvious; there’s always a line or two of code that is there purely for the benefit of IE...

This is also a good stage to mention using good programming practices; JavaScript is a very loose language, but it doesn't mean your code has to be loose too. Using tools like JSLint you can make sure that you don’t accidentally start using a variable without declaring it – that will make no sense whatsoever to someone picking up development.

For the work I was doing I knew the code may be used elsewhere as well, so I knew I had to sandbox the code so it didn't have any unnecessary dependencies. I decided to convert a series of procedural functions and statements and encase it in a jQuery plugin. This helped me create something that was reusable, highly customisable and importantly, very easy to implement for others. It also gives any developers using the plugin the option to use some basic API calls to run certain functions when their code is ready to, giving developers a good level of control.

As a result, re-writing the code has added roughly an extra 30% of code to replicate the functionality, but I’ve also added to it too. So you might be worrying that it negatively impacts the user, but there are steps you can take to make sure you get the best of both worlds.

Stick native. Despite building a jQuery plugin I have written native JavaScript where possible; for example, loops are typical for loops rather than using jQuery .each loops. Most, if not all, selectors are written to best use native DOM operations such as getElementByID(), or on modern browsers useful features like querySelectorAll(). Any complex and non-native selectors I’ve broken down so that I use the nearest ID, element or class selector and simply .find() or .filter() within the collection. Read up on jQuery performance, you’d be surprised by the difference it makes.

Put time aside for code re-factoring As your code grows it’s very likely that you will repeat functionality, whether it’s duplicating some code in a multiple-condition block or repeating an action in two different functions. During this process you might also notice a better way to do what you’re trying to achieve and it’s also a very good opportunity to make sure you are caching.

One of the biggest benefactors in coding efficiency is caching. Caching is simple but effective. If you cache a selector, it saves you re-creating jQuery object repeatedly. Take this following code:

$("#myForm").submit(function(e){
	e.preventDefault();
	if ( $(this).validateForm() ) {
		$(this).find("input, select, textarea").attr("disabled", "disabled");
		$(this).find(".errorMessage").hide();
		$.ajax({
			url: "submit.php",
			data: $(this).serialize(),
			success: function () {
				$(this).find("input, select, textarea").removeAttr("disabled");
				$(this).find(".successMessage").show();
			}
		});
	} else {
		$(this).find(".errorMessage").show();
	}	
});

Notice how many times we create a jQuery object using “this”. Instead, we could cache “this” as a jQuery object in a variable which would save us from re-creating the object, like so:

$("#myForm").submit(function(e){
	var thisForm = $(this);
	e.preventDefault();
	if ( thisForm.validateForm() ) {
		thisForm.find("input, select, textarea").attr("disabled", "disabled");
		thisForm.find(".errorMessage").hide();
		$.ajax({
			url: "submit.php",
			data: thisForm.serialize(),
			success: function () {
				thisForm.find("input, select, textarea").removeAttr("disabled");
				thisForm.find(".successMessage").show();
			}
		});
	} else {
		thisForm.find(".errorMessage").show();
	}	
});

It might not seem a lot but each slice of processing time saved soon adds up, imagine if this was inside a loop that was executed hundreds or thousands of times.

Don’t forget to chain! One of the things with creating a jQuery plugin is that when the plugin is instantiated it will return back the jQuery collection from the original selector. Why is this important? It’s important because we can do multiple actions to a collection without recreating the collection. So it’s a bit like caching too.

$(".successMessage").addClass("highlight");
$(".successMessage").slideDown();	
$(".successMessage").css("marginBottom", "20px");

3 lines of code could effectively become one:

$(".successMessage").addClass("highlight").slideDown().css("marginBottom", "20px");

There’s nothing wrong with chaining to your cached objects either, just be careful of jQuery methods that don’t return the collection e.g. serialize().

If we put all that together we get well documented code that the next developer can pick up and understand, while also keeping our user’s experiences as streamlined as possible.

So what is more important; focusing primarily on efficiency or making your code as readable and understandable as possible? In my opinion the latter wins, hands down, (almost) every time. Just because it’s readable doesn't mean it has to be bloated; minifying and clever programming can make that readable code extremely performance efficient.

Comments