• You are currently browsing the archives for the performance category.

  • Archive for the ‘performance’ Category

    The great implementer swindle – making badge use easy doesn’t make it clever!

    Tuesday, February 12th, 2008

    No matter how you’ll turn it – the future of web design will not revolve around pages and sites but around modules. The social web and the systems providing canvasses to put up applications and badges is here and will be here to stay.
    This is cool as it puts the end user much more in control of their own experience. However it is also bad as it means the standards we tried to set up and follow in the last, err 9 years are rapidly going down the drain.

    The main reason is the promise of “quick wins” and “low hanging fruit” and once again the attempt to use technology to make the web a WYSIWYG and drag and drop interface.

    Here’s my latest find that made me wonder why we don’t learn from errors of the past – making things easy to implement is not the same as making them easy to use!

    Consider the job to be to offer third parties a chance to add a badge to their site. Not hard at all – the main task is really on the implementation level, i.e. making sure the styles of the parent side don’t clobber the badge.

    Easy to implement badges

    Now, to make it easy for the implementers, here’s the proposal:

    
    <script src="badge.js" size="small" skin="blue">Brandname</script>
    

    Implementers can choose the size and the skin in attributes and give a brand name to display. This is pretty easy to understand and the script to make it work is no voodoo either:

    
    (badge = function(){
    var s = document.getElementsByTagName('script');
    for(var i=0;s[i];i++){
    if(s[i].getAttribute('src')  'badge.js'){
    var div = document.createElement('div');
    var content = s[i].firstChild.nodeValue;
    div.innerHTML = '<p>Awesome badge! </p>';
    div.appendChild(document.createTextNode(content));
    var size = s[i].getAttribute('size');
    var skin = s[i].getAttribute('skin');
    var col,width;
    switch(size){
    case 'small':width = 100;break;
    case 'large':width = 400;break;
    default:width = 200;break;
    }
    switch(skin){
    case 'blue':col = '#ccf';break;
    case 'green':col = '#cfc';break;
    default:col = '#ccc';break;
    }
    div.style.background = col;
    div.style.width = width + 'px';
    s[i].parentNode.replaceChild(div,s[i]);
    }
    }
    })();
    

    You loop through all script elements, compare the src with yours, read the attributes and the element content, assemble a badge, set the visual style and replace the script with the badge.

    This makes implementation a breeze and allows the implementer even to choose the size and colour for each badge they use.

    However there are several problems with this:

    Invalid HTML

    You cannot add custom attributes to HTML nilly-willy as it makes your HTML invalid. This is a tough one to make people understand as HTML validation is considered a nice-to-have than a real necessity. Years of lax browsers have made us immune to that issue. And, actually you could work around that with a custom DTD!

    If you wondered if adding a src and content in the SCRIPT is invalid HTML - it isn’t. All the recommendations say is that user agents should ignore what is in the SCRIPT when there is a src attribute:

    The script may be defined within the contents of the SCRIPT element or in an external file. If the src attribute is not set, user agents must interpret the contents of the element as the script. If the src has a URI value, user agents must ignore the element’s contents and retrieve the script via the URI. Note that the charset attribute refers to the character encoding of the script designated by the src attribute; it does not concern the content of the SCRIPT element.

    Poor Performance.

    This way of adding a badge loads the badge.js file for every instance. While it may be cached this is still an unnecessary overhead. The other issue is that every SCRIPT element makes the browser stop rendering until the script inside it or the one it links to with the src attribute is executed.

    The more scripts you have in your document body, the slower your site will be! I can safely say that most of my firefox crashes are because of third party JS includes (really: ads). As a real badge implementation would do more HTTP calls – most of the time directly after rendering – this would add even more overhead.

    Bad Accessibility and SEO

    Non-JavaScript clients (like search robots) will not find anything with this kind of badge. Screen readers might get the badge but the replacement of a script after calling itself must be hard to stomach for any engine that ties into the browser’s DOM.

    Alternative proposals

    All of the following proposals here do require more of the implementer, but also make sure that none of the above problems occur. Using progressive enhancement we change a valid HTML structure that can be indexed by search spiders and end up with the same result.

    All solutions work with one script include – in this case at the end of the document, but with an onload tweak this could also be in the head. This means the HTTP overhead is much less and your script does not get hit hard by every implementation.

    Full-on progressive enhancement with a server-side fallback

    This solution simply uses links to a proper backend solution that’ll offer a landing page for each brand. This means proper SEO as the links can be followed and the landing page becomes a starting point. The properties of the badge are URL parameters. While not all of them must be used by the server-side fallback they still can. You can never have too much data.

    
    <div class="fpebadge"><a href="http://realurl?brand=brandname1&skin=green&size=small">Information sponsored by brandname1</a></div>
    <div class="fpebadge"><a href="http://realurl?brand=brandname2&skin=blue&size=large">Information sponsored by brandname2</a></div>
    <div class="fpebadge"><a href="http://realurl?brand=brandname3">Information sponsored by brandname3</a></div>
    

    The script is not hard:

    
    (fpebadge = function(){
    var divs = document.getElementsByTagName('div');
    var b = [];
    for(var i=0;divs[i];i++){
    if(divs[i].className.indexOf('fpebadge') ! -1){
    b.push(divs[i]);
    }
    }
    for(var i=0;b[i];i++){
    var link = b[i].getElementsByTagName(‘a’)[0];
    if(link){
    var urldata = link.getAttribute(‘href’);
    var badgecfg = convertURL(urldata);
    var div = buildBadge(badgecfg);
    if(div){
    b[i].parentNode.replaceChild(div,b[i]);
    }
    }
    }
    function buildBadge(badgecfg){
    if(badgecfg){
    var div = document.createElement(‘div’);
    div.innerHTML = &#8216;<p>Awesome badge! </p>&#8216;;
    if(badgecfg.brand){
    div.appendChild(document.createTextNode(badgecfg.brand));
    }
    var col,width;
    switch(badgecfg.size){
    case &#8216;small&#8217;:width = 100;break;
    case &#8216;large&#8217;:width = 400;break;
    default:width = 200;break;
    }
    switch(badgecfg.skin){
    case &#8216;blue&#8217;:col = &#8216;#ccf&#8217;;break;
    case &#8216;green&#8217;: col = &#8216;#cfc&#8217;;break;
    default:col = &#8216;#ccc&#8217;;break;
    }
    div.style.background = col;
    div.style.width = width + &#8216;px&#8217;;
    return div;
    }
    }
    function convertURL(urldata){
    if(urldata.indexOf(&#8216;?&#8217;)!==-1){
    var chunks = urldata.split(&#8216;?&#8217;)[1].split(&#8216;&#38;&#8217;);
    var badgecfg = {};
    for(var i=0,j=chunks.length;i<j;i++){
    var vp = chunks[j].split(&#8216;=&#8217;);
    badgecfg[vp[0]] = vp[1];
    }
    }
    return badgecfg;
    }
    })();
    

    Progressive enhancement with a server-side landing page

    If you don’t want to provide a branded landing page, but just have the name displayed and if you don’t trust your implementers to be able to properly encode ampersands :) then you can also just have a landing page and keep the badge properties in class names:

    
    &lt;div&nbsp;class="landingbadge&nbsp;skin-green&nbsp;size-small"&gt;&lt;a&nbsp;href="http://realurl?brand=brandname1"&gt;Information&nbsp;sponsored&nbsp;by&nbsp;brandname1&lt;/a&gt;&lt;/div&gt;
    &lt;div&nbsp;class="landingbadge&nbsp;skin-blue&nbsp;size-large"&gt;&lt;a&nbsp;href="http://realurl?brand=brandname2"&gt;Information&nbsp;sponsored&nbsp;by&nbsp;brandname2&lt;/a&gt;&lt;/div&gt;
    

    The code is not much different:

    
    (pebadge&nbsp;=&nbsp;function(){
    var&nbsp;divs&nbsp;=&nbsp;document.getElementsByTagName('div');
    var&nbsp;b&nbsp;=&nbsp;[];
    for(var&nbsp;i=0;divs[i];i++){
    if(divs[i].className.indexOf('landingbadge')&nbsp;!==&nbsp;-1){
    b.push(divs[i]);
    }
    }
    for(var&nbsp;i=0;b[i];i++){
    var&nbsp;badgecfg&nbsp;=&nbsp;convertClassData(b[i].className);
    var&nbsp;link&nbsp;=&nbsp;b[i].getElementsByTagName('a')[0];
    if(link){
    var&nbsp;linkdata&nbsp;=&nbsp;link.getAttribute('href').split('brand=')[1];
    badgecfg.brand&nbsp;=&nbsp;linkdata;
    }
    var&nbsp;div&nbsp;=&nbsp;buildBadge(badgecfg);
    if(div){
    b[i].parentNode.replaceChild(div,b[i]);
    }
    }
    function&nbsp;buildBadge(badgecfg){
    if(badgecfg){
    var&nbsp;div&nbsp;=&nbsp;document.createElement('div');
    div.innerHTML&nbsp;=&nbsp;'&lt;p&gt;Awesome&nbsp;badge!&nbsp;&lt;/p&gt;';
    if(badgecfg.brand){
    div.appendChild(document.createTextNode(badgecfg.brand));
    }
    var&nbsp;col,width;
    switch(badgecfg.size){
    case&nbsp;'small':width&nbsp;=&nbsp;100;break;
    case&nbsp;'large':width&nbsp;=&nbsp;400;break;
    default:width&nbsp;=&nbsp;200;break;
    }
    switch(badgecfg.skin){
    case&nbsp;'blue':col&nbsp;=&nbsp;'#ccf';break;
    case&nbsp;'green':&nbsp;col&nbsp;=&nbsp;'#cfc';break;
    default:col&nbsp;=&nbsp;'#ccc';break;
    }
    div.style.background&nbsp;=&nbsp;col;
    div.style.width&nbsp;=&nbsp;width&nbsp;+&nbsp;'px';
    return&nbsp;div;
    }
    }
    function&nbsp;convertClassData(c){
    var&nbsp;chunks&nbsp;=&nbsp;c.split('&nbsp;');
    var&nbsp;badgecfg&nbsp;=&nbsp;{};
    for(var&nbsp;i=0,j=chunks.length;i&lt;j;i++){
    var&nbsp;vp&nbsp;=&nbsp;chunks[j].split('-');
    if(vp[1]){
    badgecfg[vp[0]]&nbsp;=&nbsp;vp[1];
    }
    }
    return&nbsp;badgecfg;
    }
    })();
    

    Hey, you use classes, why not provide a skin file?

    Seeing that the last option actually uses classes, why not leave the styling to CSS and offer some skinning files the implementer can change? That way your badge script would be very small indeed:

    
    (pebadge&nbsp;=&nbsp;function(){
    var&nbsp;divs&nbsp;=&nbsp;document.getElementsByTagName('div');
    var&nbsp;b&nbsp;=&nbsp;[];
    for(var&nbsp;i=0;divs[i];i++){
    if(divs[i].className.indexOf('skinnedbadge')&nbsp;!==&nbsp;-1){
    b.push(divs[i]);
    }
    }
    for(var&nbsp;i=0;b[i];i++){
    var&nbsp;link&nbsp;=&nbsp;b[i].getElementsByTagName('a')[0];
    if(link){
    var&nbsp;div&nbsp;=&nbsp;document.createElement('div');
    var&nbsp;linkdata&nbsp;=&nbsp;link.getAttribute('href').split('brand=')[1];
    div.appendChild(document.createTextNode(linkdata));
    div.innerHTML&nbsp;=&nbsp;'&lt;p&gt;Awesome&nbsp;badge!&nbsp;&lt;/p&gt;';
    b[i].parentNode.replaceChild(div,b[i]);
    }
    }
    })();
    

    You can extend that to load and apply CSS files on demand, but it’ll make more sense to keep them in one file, once again to cut down on HTTP overhead but also to use the cascade to produce small CSS files.

    Comments? You can go and try out all the examples here

    The joys and perils of working for a large corporation

    Saturday, February 9th, 2008

    This is not a technical post, but something that I’ve been pondering about for a while and it is related to a lot of comments and emails I get through here. I wanted to sum up some points what it is like to work for a large, very public corporation and what my points of view and my circle of influence are.
    Lately I’ve been getting a lot of questions about this and instead of repeating myself over and over again, I take this as an opportunity to write a reference piece.

    There comes a time in the career of a developer where you go up the hierarchy in your company. Most of the time this is because of your performance and dedication to the company but also to the wider market that you work in and due to the fact that you have proven to yourself that you are a good developer and team player.

    Web Development is a very young profession and we do make all the mistakes that have been done in other professions before. One thing is for sure though: you need to keep your eyes open and roll with the changes of the market in order to succeed. If you take your job and the fact that the web is a new media really serious this means that you need to check out future technologies and ideas as much as delivering the current ones to full satisfaction.

    If you’ve done this for several years and feel your forehead getting numb from running against walls trying to get this idea through to people whose main concern is to make enough money to be able to pay the wages and other company expenses you got two choices: start an own company, consult others or try to join one of the big players in the market.

    The former two come with financial unknowns and a lot of stress. The second also comes with the decision to let go of some of your dedication as you cannot over-deliver. You consult, you invoice, you hope they get better and you leave for the next job. You know what to do right, but you hardly ever get the chance to really deliver it.

    The latter – working for a future-facing, established corporation that is not in trouble – comes with a lot of positives:

    • You work for a company that has been around a while and knows how to treat employees so that they can deliver (this means HR issues are taken care of and the pay is no problem either)
    • You work for a company that already has a lot of developers working for it and doesn’t have to start understanding the value of good IT support. This includes getting adequate hardware, the right software and upgrades whenever they are necessary rather than when they fit the budget.
    • You get reach beyond your wildest dreams – millions of users – and learn about tricks of the trade you never thought necessary but that are when you want to deliver a great experience for all these people.
    • You get the chance to work with amazingly skilled people – those whose books you read and wondered how the hell they come up with great ideas like that.
    • You get to propose people you always wanted to work with to get hired – and find that there is a budget for that!
    • You find that there are departments in the company that research technologies and ideas that aren’t an immediate success but will be a great asset in the future. You even get kudos and maybe even more for proposing them some ideas.
    • You can learn from the massive experience of people that have been playing in this league for a long time.
    • You get company perks (free food, cheaper hardware, gym, health care and so on…)

    All of this will make you happy but there is a flipside, too.

    • You are a geek, possibly even with a “scene” background and you “sell out to the man” in the eyes of a lot of people that saw you as an equal before.
    • People expect you to change drastically and you have to suffer many “tongue-in-cheek” comments about you “being assimilated”, “joining the mothership” and other “clever” remarks.
    • Whenever you talk about a product of your company, people will take it less serious than when you said the same prior joining the company. “Of course you say this is good, they pay you for it”.
    • You will be responsible for everything your company does, no matter how far removed from your area of expertise or even location it happens.
    • You will be judged not by the good stuff that happens but by the lower quality things the company produces – it is fun to poke the giant and show that you can do things better (whilst forgetting the dependencies the giant has to support that you don’t have to)
    • Naturally you will be considered to have insight into all the happenings in the company and probably can tell in detail whatever people might want to know.
    • It is expected that if somebody wants you to work for them (for example as a speaker at a conference) your company will gladly pay for your travel there and the accommodation and not the organization that wants you to work for them.
    • You are expected to be as rich as the richest director in the company, as all the goods are shared equally, right?
    • You will know what stocks to invest in as your company is big in Wall Street
    • You can get anyone a job in your company, even if they haven’t the faintest clue what they really want to do or what they can bring to the table.

    Each of these is no biggie and you can shrug them off, but it is amazing how many of these happen day in and day out.

    So here is what I do and know about my company and its future:

    • I work as a web architect, giving advice on frontend web development matters to the people who build the internal tools that we build our web sites with.
    • I am part of a team whose job it is to define the standards frontend web matters are delivered to.
    • I am working on internal tools to make it easier to re-use code and components across different products.
    • I propose people to hire and interview others for positions in web development
    • I am an external European arm of our development library and can offer information and talks about that
    • I am a speaker that can talk about all the public facing APIs, libraries and components we offer for outside developers
    • I am an internal trainer on all matters web development and human interaction (accessibility, writing for the web…)
    • I am reviewing internal code and products of Europe, Asia and sometimes the US
    • I talk a lot to teams in the US to make sure our standards tie in with their ideas and will become global standards
    • I talk to universities about hack days, challenges and other academic happenings.
    • I keep an eye on the team in Europe and around the globe to make sure that developers are happy and can do a good job – removing obstacles for them and talking people out of ideas that would mean a lot of work for the web developers without much gain.
    • I liaise with other people in the same positions and HR and PR to make sure we have some processes in place that will ensure that we can hire good people in the future and give potential new developers an insight into what it means to be a developer for a large site like ours.
    • I speak to the backend teams to ensure we work together smoothly and have methodologies that work hand-in-hand.

    This is a lot, and it keeps me busy with the things I care about the most – cool technology that benefits web surfers and empowering people who want to build this technology.

    In short, I talk a lot to developers, their managers and outside people about our technologies to make sure that we can deliver good products and have fun experimenting with new ideas.

    And that is all that I know about in my company. Anything else, I’d venture to guess that you know more than I do!

    YUI on the go – load YUI components on demand

    Friday, December 7th, 2007

    This is one of my talks at the Yahoo! Frontend Engineering summit in London and it deals with the options of cutting down the size of the YUI library components. There have been many articles and posts about this subject already but none really explained the idea of using YAHOO_config to load components on demand instead of using the YUI loader.

    This is also the trick I used to create the unobtrusive flickr badge v2.

    [tags]yahoof2elondon07,webdevelopmentsummit,yahoo,yui,javascript,lazyload,widgets,badges,performance,speed,webdevtrick[/tags]