Thursday, May 26, 2011

Remembering jQuery UI Accordion Selections

The jQuery UI accordion widget is a great way to group logical sections of your page together.  The accordion widget is actually an alternative to the tabs widget - they're both just layout containers.

So if I'm using an accordion widget as the main layout component on one of my pages, it would be nice if we had a way to preserve the selected section.  My approach to this is by using hashes in the URL.  Below is the basic HTML markup:

<html>
    <head>
        
        <title>jQuery UI Accordion Selection</title>
        
        <link type="text/css" href="jqueryuitheme.css" rel="stylesheet"/>
        <script type="text/javascript" src="jquery.min.js"></script>
        <script type="text/javascript" src="jqueryui.min.js"></script>
        <script type="text/javascript" src="accordion.js"></script>
        
    </head>
    <body>
        
        <div id="accordion">
            <h3><a href="#section1">Section 1</a></h3>
            <div>
                Section 1 content...
            </div>
            <h3><a href="#section2">Section 2</a></h3>
            <div>
                Section 2 content...
            </div>
            <h3><a href="#section3">Section 3</a></h3>
            <div>
                Section 3 content...
            </div>
        </div>
                    
    </body>
</html>

And here is the accordion.js file:

$(document).ready(function(){
    
    //Get the selected accordion index, based on the URL hash.
    var index = $('#accordion h3').index(
                $('#accordion h3 a[href="'+window.location.hash+'"]')
                .parent());
                
    //The index will be -1 if there is no hash in the URL.  This
    //is necessary if we want the first section expanded by default.
    if (index < 0){
        
        index = 0;
        
    }
    
    //The change event handler will add the hash to the URL when
    //a section is selected.
    var change = function(event, ui){
    
        window.location.hash = ui.newHeader.children('a').attr('href');
        
    }
       
    //Build the accordion, using the URL hash selection and the
    //change event handler.
    $('#accordion').accordion({active: index,
                               change: change});
                                   
});

We can now use the URL hash to set the accordion selection.  This is how it works:

The first variable - index - is the index of the accordion selection.  So 0 is the first accordion section, 1 the second, and so on.  This selector is a little tricky because inside the #accordion div, we have alternating h3 and div elements, so the h3 indexes aren't linear.  To get around this, we have two selectors.  The first one filters out all the h3 elements we're interested in.  Now that we have only h3 elements, we can call index() on them - we won't get invalid indexes due to intermingled divs.  We pass index() the h3 element we're interested in, namely, the one with the a that has an href matching the current URL hash.

Phew, so now we've got an index we can use to select the appropriate section.  Or do we?  If the user is visiting this page for the first time, there won't be any hash in the URL.  This means the value of index will be -1.  We don't want that, so we give it a value of 0 if there is now real index to use.  This way the first section is active be default.  This is the expected behaviour, I would say, 99% of the time.

Next, we define an event handler - change - that is triggered when the user changes accordion sections.  All this handler does is set the URL hash, allowing the default functionality associated with changing sections to run normally.  For example, changing to section two in our example will add #section2 to the URL.

Finally, we build the accordion widget using the selected index and the change event handler.  This isn't a perfect solution, but it does solve some headaches with accordion widgets - like the back button and bookmarks.

Wednesday, May 25, 2011

Interface Connection Thinking

Software object systems, are a collection of objects, connected by relationships. Typically, objects are connected by structural relationships. I can think of a dozen real-world analogies when I'm writing code. When I think of these analogies, I'm thinking about the physical structure of the buildings, cars, engines, books, anything really, that inspires my software design. This is why object-oriented software uses the object as the fundamental unit, not the behaviour. We don't focus on the behaviour of our software when we're designing it. At least it isn't the first thing we consider when starting a new project. I don't think “what are the major behavioural components of this system”? The first thing that comes to mind when building from scratch is something along the lines of “what are the fundamental data structures I'll need to make this work?”. Maybe this approach is backward.

Emphasis on the data structures taking precedence over how the software works – the moving parts of the system – is hard to overcome because we're so used to making analogies to real-world objects and their properties. This is an essential feature of our brain – if you cannot distinguish between dangerous objects and irrelevant objects or beneficial objects, your chances of survival are slim to say the least. We differentiate between objects in the real-world based on their attributes – the things we can see. We recognize objects by nothing more than their physical attributes – their shape, their colour. My desk I work at everyday stands out relative to every other desk in the office because of its attributes. The monitor, the coffee mug, the unsorted pile of paper – all things that make the desk unique and recognizable.

This isn't to say that we don't make analogies with regard to how things function, the way they move or produce output. My desk, of course doesn't do anything very interesting, or anything at all for that matter. It just sits there – I have no real need to compare what it does to anything else. My car, on the other hand, has several interesting characteristics other than its less-tangible attributes. I can use these to make comparisons - to other cars, or other objects. The car moves – hopefully in more than one direction. It has a maximum speed and it turns. I could go on, but that would be overkill. Clearly, we're capable of making behavioural analogies too. The question is, why do we favour the structural when it comes to software design?

As we know, software is a host of objects connected to one another. I'm not sure there is as much a distinction between structural and behavioural aspects as we might think. The structure of software objects is like glue - it prevents an objects from becoming unraveled and going rogue in the system. When we're thinking abstractly, we're thinking that structure equals order. If we could only build the perfect foundation, we could add the required functionality on top. Everything will work better than it would had we not built a solid base. I'm not sure this is the correct view to take.

My reasoning is simple – interfaces describe what an object does, and suggests some structural attributes the object might have, based on its name. Interfaces are concrete in their behavioural descriptions and tentative in their structural descriptions. This is because interfaces give all the necessary details for implementing the interface methods – the behaviour. If the interface has a good, descriptive name, you can glean some potential attributes that support the implementation. The objects attributes aren't part of the interface contract whereas the operations are. This is important, I think, for at least some degree of implementation freedom. Whats really important with interface connections is that clients get what they expect from their suppliers.

Suppose we've got an IReader interface that requires a read() method be implemented by any objects that provide the interface. The read() method is supposed to return data. How it does this, exactly, is up to the implementation. Maybe the data is read from a file, maybe from an attribute stored in memory, maybe from a network connection. These are all implementation concerns, not that of the interface. The interface serves as a connector, putting the emphasis on what that implementing object does. The client object knows what it needs, in the case of the IReader interface, it needs an object that can read data.

So how does thinking in interface connections result in better software? I think it takes the focus away from the structural properties of objects and places it on the behavioural descriptions. Objects still have attributes, even when we're emphasizing the interface connections. However, these are more closely tied to the implementation than the design. Connecting objects by what they do is how you connect objects by design instead of by implementation.

Friday, May 13, 2011

Distributed Cloud Providers

Cloud computing is all about distributing your resources across several physical nodes. We enjoy this tactic for several reasons – redundancy, concurrency, and generally feeling good about having a legion of computers at your disposal. Another attractive feature of the cloud is that it does all hard work for us, behind the scenes. We select a provider based on their advertised features. They'll make our lives better, so they say. As we saw last month with the Amazon EC2 outage, there is no real protection against what can go wrong with any service provider, be it cloud, or some other service. Failure isn't restricted to any one provider. Amazon is the king of cloud computing providers, and they've got a great service 99% of the time. Putting all your faith in a single provider, however, means that the repercussions of downtime are exemplified. Examples like these illustrate why those using the cloud need to distribute amongst cloud providers.

Think about investing your money. You've got your savings account at the bank. You've just received a bonus and the first thing that comes to mind is to save it. Alternatively, you've now got a little money you can use to invest in that company you've been watching, or maybe you're concerned about the all-mighty dollar and want to buy some gold bullion. Regardless of where you put your money, having it all in one place is dangerous. If you invest all your capital in a company that flops, you feel 100% of the collapse. Likewise, if the company is a soaring success, you feel 100% of the positive outcome. Its simple risk management, and its really no different from choosing a cloud provider, or diversifying across several cloud providers.

Starting a web company usually requires a lot of compute capacity, guaranteed up-time, and so on. Going with the name brand only makes sense. Most likely, you'll invest 100% of your efforts with this one perfect provider with a near flawless reputation. Consequently, you'll get 100% of their awesomeness - when they're being awesome. Not to mechanically pick on Amazon, but its just a perfect illustration of my point – when the provider is down, or slow, or decided to make fun of you that day, you'll get 100% of their meagerness, with nothing else to fall back on.

We've seen cloud providers going down over the past several years, and these are caused by internal issues. The provider's infrastructure is experiencing some kind of bug, hardware failure, whatever. They're generally not transparent in communicating the details of these issues to end users. Providers assume that cloud computing consumers don't necessarily care about this kind of thing. And they're probably right, for the most part. Users of cloud services mostly just want they're systems up and running, everything else is secondary. However, we're not limited to internal failures of the provider's infrastructure.

Nothing stops a provider from changing some fundamental aspect of their system. The API could change, a minor annoyance but nonetheless important for consumers. Maybe their policies change regarding QOS or maybe their performance characteristics go down the tubes for one reason or another. Externally, changes like these don't really affect the perception of the provider quality - they're functional, up-time is maintained, etc. They appear to be working as expected but these small changes can have drastic consequences for consumers. Changes such as these introduced by the provider don't even need to be technological to have an impact. As a consumer of a single service provider, imagine the cost spikes. You're stuck with incurring 100% of the increase. If you distribute your cloud technology across providers, maybe you only have to take 20% of the hit.

The trouble is that a single service provider isn't a market, it only appears that way. Providers offer different hardware resources at different costs. You can browse these offerings and choose one that is cost-effective. However, you're still stuck with the brand. Cloud providers are like an outlet store – you can shop for good deals on products made by the same manufacturer. You can't necessarily compare characteristics of the provider that fall outside of the technical specifications of what they're offering. This includes things like bad past experiences – if a service provider has failed you in the past, their brand will leave a sour taste in your mouth.

The answer for cloud consumers is to distribute their activities across providers. The solution isn't as straightforward as it may sound. If you're in the business of making software that runs in the cloud, you're probably not interested in searching the web for good providers as you would a for a new laptop. No, you need an actual market. If a cloud provider is like an outlet store, than we need a shopping mall filled with nothing but cloud outlets. This is what we're trying to do with SpotCloud. We didn't design it with provider diversity in mind, however, it certainly seems relevant these days.

Building your application on one cloud provider is enough of a challenge, let alone trying to distribute amongst several cloud providers. Who supports what features you need? In SpotCloud, you've got a minimal feature set – instances minus the bells and whistles. It takes one piece of the cloud diversity out of the equation – finding the right provider. The hard part is building software for the cloud, but I think that is best left to the developer – inventing ways to use instances profitably. The cloud market, be it SpotCloud or something else, is a necessary tool if we're not going to be constrained by provider's technological and business decisions.

Tuesday, May 10, 2011

jQuery UI URL Tabs

The jQuery UI toolkit provides us with a tabs widget to logically group elements on our page.  This is useful as a top-level navigational tool for most web applications.  The default functionality of this widget allows us to divide content on a single page into tabs.  This is good if every page in your application has a different set of tabs, obviously not well suited for top-level navigation.

We can also configure the jQuery UI tabs widget to load the individual tab content in the background using Ajax requests.  Using this approach, we can reuse the same widget on several pages.  However, maybe we don't want to use asynchronous HTTP requests.  If your application doesn't use it anywhere else, why use it for the top-level navigation?

This also introduces another problem - if you're using the tabs widget as a top-level navigation tool, you probably want the links displayed to the user so they can visit these pages directly.  The tabs demo page actually has a work-around that lets the user follow the link set in the tab.  So it almost behaves like a link, but there is a problem with this approach in that it still appear to be a link to the end user.  For example, they can't right click it and copy link address.  It would be nice if we could use the tabs widget as a top-level navigation widget that uses standard links.  This way we can theme it and attach additional behavior to it if we're so inclined.

Below is an example of how I was able to get this working.  Here is the basic HTML markup.

<html>
    <head>
        
        <title>jQuery UI URL Tabs</title>
        
        <link type="text/css" href="jqueryuitheme.css" rel="stylesheet"/>
        <script type="text/javascript" src="jquery.min.js"></script>
        <script type="text/javascript" src="jqueryui.min.js"></script>
        <script type="text/javascript" src="urltabs.js"></script>
        
    </head>
    <body>
    
        <div id="tabs">
            <ul>
                <li><a href="/page1/">Page 1</a></li>
                <li><a href="/page2/#content">Page 2</a></li>
                <li><a href="/page3/">Page 3</a></li>
            </ul>            
            <div id="content">                 
                <p>Some content...</p>
            </div>
        </div>
                    
    </body>
</html>

And here is the urltabs.js file used to create the widget.

$(document).ready(function(){
    
    //Get the selected tab, and it's URL.
    var selection = $('#tabs ul li a[href$="#content"]');
    var selection_url = selection.attr('href')
                                 .replace('#content', '');
                                 
    //Replace the #content href.
    selection.attr('href', '#content');
    
    //Create the tabs widget, and select the proper tab.
    $('#tabs').tabs({
        selected: selection.parent().index(),
    });
    
    //Make each tab a link by setting the href attribute.
    $('#tabs ul li a').each(function(){
        var url = $.data(this, 'load.tabs');
        if(url) {
            $(this).attr('href', url);
        }
        else {
            $(this).attr('href', selection_url);
        }
    });
    
    //Make sure the selected tab also behaves like a link.
    $('#tabs ul li.ui-tabs-selected a').click(function(){
        location.href = $(this).attr('href');
        return false;
    }).css('cursor', 'pointer');

});

And there you have it - a tabs widget that will behave like plain old links.  Now for a few explanations.

The central idea to this approach is that the HTML markup uses a central #content div for displaying the selected tab content.  The selected tab link URL uses this anchor to say "I'm currently selected".  The markup is fairly simple and can easily be handled by any template system and server-side menu constructs.

The construction of the widget itself is done in five steps.  First, we need to locate the currently selected tab and store its URL.  We do this by finding the link with #content at the end.  Next, we replace the URL with #content.  This is required in order to display any content.  Next, we actually create the tabs widget using the specified tab selection.  At this point, we have a tabs widget, but it still wont use regular URL links because the widget will intercept the click events.

There are two things left to do once the widget has been created.  First, we find all tab links and set their URL back to what it was originally, before the widget was created.  However, the selected tab is different - we cannot retrieve the original URL from the widget and so this is why we stored it before the widget was created in selection_url.  Finally, we make the currently selected tab a link too.  Users will intuitively try to click it, so we may as well give them what they want.