Date post: | 19-Aug-2014 |
Category: |
Education |
Upload: | christian-heilmann |
View: | 23,782 times |
Download: | 1 times |
Scripting
Maintainability
Christian Heilmann
Fronteers Conference 2008, Amsterdam, Holland
Hello there, I’m Chris.
I’m here to talk about maintainability of code.
Which really is not that easy.
I was also asked to deep-dive into the subject.
Oh well, let’s do this.
Humans and computers don’t work well together.
Computers love things structured and logical.
Humans, on the other hand like to tweak, fiddle and find
their own way.
Photo of a desire
path – a shortcut people
take to avoid having to go around a corner.
http://www.flickr.com/photos/skuds/602082016/
Humans also love to
bend the rules.
Photo of a parking lot with a barrier and
tire marks around the barrier on each side.
All of this makes it damn hard to create maintainable
products.
Especially in our market, as we are dealing with geeks.
Photo of a geek.
Finding easily maintainable code is very rare.
The reasons are several tales of woe:
The Village Bicycle Syndrome
The Pot Noodle Syndrome
The Lego Box
The Tale of the Missing Spanish Gentleman
The Truffle Shuffle
The village bicycle is where everyone can have a ride.
Sadly, this is what JavaScript has become, too.
Backend Engineer
Designer
SystemServerAdmin
JavaScript
Each of these will approach JavaScript in a different
manner and leave their own brand of confusion behind.
Unlike the village bicycle they are not likely to help
keeping it in a working condition.
Mainly because each of these comes in with a different idea
of what JavaScript is for.
We have to find a way to work around this – more on
that later.
However, a lot of hit & run editing is the cause for the
second syndrome.
The pot noodle syndrome is that your code turns into an
instant meal.
Cheap, hot, quick, immediately satisfying and
something you can prepare in any state of mind and
intoxication.
The problem of pot noodle code is that it is far too easy
to sell and get accustomed to.
Shortcuts don’t take much time and give you instant
success.
One of the signs of pot noodle code is that it fixes short term
issues with not much effort.
It is the kind of code that someone with delusions of knowledge adds quickly, shows to a manager and
proves thus that you “experts” overcomplicate
everything.
Examples:
Inline style blocks, innerHTML solutions to create complex
HTML, trusting user data, Ajax requests without timeout or
failure cases.
user = forms.main.name.value;if(user == ‘’){div = document.createElement(‘div’);div.style.border = ‘1px solid red’;// div.style.fontface = ‘Arial’div.innerHTML = ‘<font face=arial color=red>Enter a user Name!’;error = document.getElementById(‘error’);error.appendChild(div);
}
Which leads to the other tale: The Lego box.
As a kid, I had this massive box with all my Lego bricks.
Being the youngest, I inherited a vast and totally unordered arrangement of
bricks.
Which meant that whenever I built something, about 80% of
my time was spent rummaging noisily through
the box...
...scattering bricks all over the room and still not finding
what I was looking for.
...which of course drove my mom up the wall at 6 a.m.
...so she got me lots of little boxes and we spent a few
days organizing all the bricks into those.
The things I build afterwards were much prettier, more
complex and I was building them a lot faster.
I didn’t break any bricks rummaging or stepping on
them and the noise level was much lower.
The same can work for code.
By separating the different tasks into the right boxes, we
stop the pot noodle syndrome.
Everything visual is achieved with CSS!
HTML that makes sense without JavaScript should not
be created with JavaScript.
HTML that *only* makes sense *with* JavaScript should be created with
JavaScript.
Anything that is likely to change should not be
scattered all over your code but in a central location.
Let’s take a look at an example.
Screenshot of
the Yahoo Music API
video player.
http://ydntest.com/musicapi/playerfull.html
Everybody Duck!
There will be code
function videosreceived(data){ // create a new video player container var player = document.createElement('div'); player.id = 'videocontainer'; document.body.appendChild(player); // inject the video player with the id 'videoplayer' var so = new SWFObject('http://d.yimg.com/cosmos.bcst.'+ 'yahoo.com/up/fop/embedflv/swf/fop.swf','videoplayer','512', '322', '9', '#ffffff'); so.addVariable('eID','1301797'); so.addVariable('ympsc','4195351'); so.addVariable('lang','en'); so.addVariable('shareEnable','1'); so.addParam("allowFullScreen","true"); so.addVariable('enableFullScreen','1'); so.addVariable('autoStart','0'); so.addVariable('eh','bandsPlayer.handler'); so.addParam('allowScriptAccess','always'); so.write('videocontainer');
// get a reference to the video player - this needs to be global! vidplayer = document.getElementById('videoplayer');
var videos = data.Videos.Video; var list = document.createElement('ul'); for(var i=0,j=videos.length;i<j;i++){ var title = videos[i].title; var id = videos[i].id; var photo = videos[i].Image.url; // resize photo photo = photo.replace('=385','=75'); // turn duration into minutes and seconds var duration = videos[i].duration; var mins = parseInt(duration/60); var seconds = duration % 60; if(seconds < 10){ seconds = '0' + seconds; } duration = mins + ':' + seconds; var id = videos[i].id; var li = document.createElement('li'); // creata a link pointing to the playID method of the movie var a = document.createElement('a'); a.setAttribute('href','javascript:vidplayer.playID("v"+'+id+')'); var img = document.createElement('img'); img.setAttribute('src',photo);
img.setAttribute('alt','Video screenshot of: ' + title); a.appendChild(img); a.appendChild(document.createTextNode(title+' ('+duration+')')); li.appendChild(a); list.appendChild(li); } document.body.appendChild(list); }
Let’s clean this up!
yahoomusicplayer = function(){ var configuration = {}; var vidplayer = 0; function init(){}; function buildplayer(id){}; function received(data){}; function sanitize(data){}; function getMinutesAndSeconds(duration){}; function createItem(videodata){}; function play(id){}; return{ init:init, received:received, play:play, config:configuration }; }(); yahoomusicplayer.init();
Configuration objects rule!
If you make them accessible, you can also allow for programmatic access.
http://www.wait-till-i.com/2008/05/23/script-configuration/
*.className is your friend!
How can you hide a lot of different elements with a
certain class in a document?
// it's 2008, baby, yeah!if(document.getElementsByClassName){ var sections = document.getElementsByClassName('hide'); for(var i=0,j=sections.length;i<j;i++){ sections[i].style.display = 'none'; }// we're still in Redmond} else { var sections = document.getElementsByTagName('div'); var check = new RegExp("(^|\\s)hide(\\s|$)"); for(var i=0,j=sections.length;i<j;i++){ if(sections[i].className.match(check)){ sections[i].style.display = 'none'; } }}
alternatively...
_x$_2_(‘hide’).libraryMagicPixies.each(this.hide(‘snappy’));
How about?
var b = document.body;var c = b.className ? b.className + ' js' : 'js';b.className = c;
body.js div.hide{ position:absolute; left:-4000px;}
You use the right tool for the job, keep the headache of
designing to those who care about it and avoid looping to
boot!
You also give the CSS designer a handle to style a
non-JavaScript and JavaScript version.
All these tips in one blog post:http://www.wait-till-i.com/2008/02/07/five-things-to-do-to-a-script-before-handing-it-over-to-the-next-developer/
The Tale of the missing Spanish Gentleman
Every product comes with a free Spanish novel.
About a man called Manual.
Spoof of an IKEA
manual explaining
JavaScript
Documentation is a lot harder than we think.
The reason is the diversity of people that will use your
script.
Biggest BS statement ever:
Good code explains itself.
“Yes that is understandable to you, as you are Dean Edwards, but I am not”
SCNR :)
The biggest issue with documentation?
How do you make sure it doesn’t get outdated?
We are very likely to update and fix code, but not the docs.
Therefore a great concept is to have at least part of the documentation generated
from comments in the code.
Big libraries do this to provide an in-depth
documentation of what is what.
... which is a cool start, and somewhat of a safety net.
... but it also poses a very high barrier of entry.
For the more visual and hands-on learners you also
need to provide step-by-step tutorials and shortcuts.
One structure for tutorials has become a very successful
blue-print:
What does it do?
Working Example
Full code
Chunks of code interspersed with explanations
You can generate this from comments in the source code
of a code example using a backend script:
http://is.gd/25A8http://icant.co.uk/sandbox/videoplayer
/*startmeta name: Yahoo Music API video player title: Detailed explanation of the demo script for the Yahoo Music API video player date: 12/09/2008 description: This is a step by step explanation of the cleaned up demo example for the Yahoo Music API video player tags: yahoo,music,api,videos version:1.0 authors:Christian Heilmann (http://wait-till-i.com) license:BSD license (http://wait-till-i.com/license.txt)endmeta*/
/*We're using the "revealing module pattern":http://www.wait-till-i.com/2007/08/22/again-with-the-module-pattern-reveal-something-to-the-world/ to define the main script. In this case, the main module name will be #yahoomusicplayer#.*/yahoomusicplayer = function(){/*The configuration object defines the things that are likely to change, in this case the IDs of the player container and the video player itself. The label is the alternative text of the videothumbnails, it will be followed by the title of the video.*/
var configuration = { CSS:{ IDs:{ playerContainer:'videocontainer', player:'videoplayer' } }, labels:{ imagealt:'Video screenshot of: ' } };[...]
Copy and Paste examples are amazingly successful.
Make very sure that they work, and that they are high
quality examples.
A lot of people will not bother learning how things work...
...but fiddle around with the examples until they do what
they are asked to create.
Documentation is never a waste of time...
... unless people don’t find it.
Make sure that new developers get on the project
from the documentation to the code – not the other way
around.
This avoids the last issue of the list.
The Truffle Shuffle
The Truffle Shuffle
It is when something that should be small is far too big
for its own good.
a.k.a.
Code Bloat
Code bloat happens when code that is not explained or structured gets in the wrong
hands.
Very often this is the case with CSS.
Instead of editing the existing CSS selectors and values,
maintainers just add another line...
...increasing the specificity by adding another selector until you end up with things like:
body div#main ul#main li a.active span{color:#000;
}
A JavaScript classic is also just to add other functions and
call them immediately at the end of the script or with another window.onload.
I’ve talked in length about this a year ago:
http://icanhaz.com/codebloatinfo
However, here are some tricks to avoid code bloat.
Separate out – each method does one and only one task.
If you are likely to need to do the same task over and over, create a tool method (f.e. creating a link, adding new script node to the head)
Collate related task methods into modules.
Document the modules:
myapp.Dom does all the the Dom manipulation.
myapp.validate does all cleaning of user data.
Explain how to extend the modules!
The most important:
Have a build process!
Live code is for machines – development code is for
humans!
Minify, strip comments, collate into a single include
file and tag as
GENERATED, DO NOT EDIT!http://www.ejeliot.com/blog/72
What about code standards?
Here’s an idea: instead of forcing developers to change their ways, let’s think about
using technology.
The place where code needs to be in an agreed standard is
inside the code repository.
The easiest way to make this work is by automatically
converting it to this format when the code is submitted.
So instead of arguing pro and cons of writing code in a
certain format, let’s script our editors to do that for us!
The safest way is straight and narrow – no confusion, no
surprise.
More reading:http://delicious.com/codepo8/forfronteers08
Thanks!Chris Heilmann
http://scriptingenabled.org
http://wait-till-i.com