better software through user-centered design

Recently I was perusing the Think Geek online catalog when I came to an item that was out of stock. It seems like there is not really an industry standard for communicating stocking quantities on your website, but some of the leading e-commerce sites do partake. If  you come to an item you want that is out of stock, it usually says in some tiny words off to the side that it is out of stock.  Harder to find stock status is more likely to lure you into purchasing that item anyway.  If you know ahead of time the item is out of stock, you are more likely to skip the purchase in favor of a competitor who has your beloved item ready to zip out the door.  By getting you to purchase an out of stock item, the site manager knows you are less likely to cancel your order, and to wait the extra week for it to arrive.  Having managed an e-commerce site previously, I witnessed this time and time again and even utilizing this knowledge for my sites benefit.

Think Geek marks an item in stock if it is such, but takes an interesting stance when it is not.  Not only does it show out of stock in the area it would otherwise show in stock, a panel folds up from the bottom of the screen with a clever message letting you know they do not have that item.  It is great that they alert you, but they also have the ability to add to wishlist or email you when the product becomes available.  Perhaps the smartest piece of this feature is that they show similar and more importantly relevant items on the panel as well. The whole feature comes together and works well because it is non-intrusive.  There is nothing important on the screen being covered by the panel as well as I can still scroll the page without the panel getting in the way.  If there was some reason I needed the panel gone, there is a handy hide button removing it from site.

From a user experience standpoint this is great because the user was obviously considered in this design.  This type of feature creates interaction points with the user where if “feels” like the site is engaging  you and helping you shop instead of just showing some images and text on a screen and hoping you buy.  Bottom line is that to me this is a great implementation of honesty in stock levels and I hope to purchase from Think Geek again soon.

Merry Christmas and a Happy New Year you all who read this post!

This is a sort of weird post, but recently I ran into an issue where I needed to transfer a bucket of email addresses from one hosting account to another.  In this case I am using Siteground as my host, and I was switching from one basic hosting account to another.  With the ultra low-priced plan you get cPanel access but no SSH or migration tools whatsoever.  There is an email account and email forwarder import tool, but no export, only showing you your email account on the screen.  The combination of laziness and geekiness overwhelmed me so I used the Firebug command line and wrote a script to export the data I needed to be imported into Excel and then uploaded to cPanel.

Ccode and steps taken to complete this task for Email Addresses:

  1. Login to cPanel on old account and click on “Email Accounts” under the Mail Section.
  2. Change the results per page to be the max.  In my case, this showed me all email account.
  3. Bring up Firebug command line and input the following code:
    var rows = $("#table_email_accts tr.dt_info_row"),
    returnString = "";
    rows.each(function(i, item){
    var tdList = [];
    $(item).find('td:eq(0)').each(function(s, subItem){
    tdList.push($(subItem).text());
    });
    returnString += tdList + "\n";
    });
    console.log(returnString);

    This code may need tweaking for your cPanel version, but you should now see a list of the email addresses you desire in the Firebug console.
  4. Create a new text document in the directory of your choosing.  Copy and paste the email addresses inro the file and save as a csv.
  5. Create a new Excel spreadsheet with 3 columns and add the labels “Address”, “Password”, and “Quota”.
  6. On the data tab choose “From Text” under Get External Data.  Select the text (csv) file you just created and open.
  7. This will import the email addresses into the first column so all that needs to be done is add the passwords and email quota.
  8. All that is left is to click the Import Addresses/Forwarders link, upload the spreadsheet and follow the on-screen instructions.

Code and steps taken to complete this task for Email Forwarders:

  1. Login to cPanel on old account and click on “Forwarders” under the Mail Section.
  2. Change the results per page to be the max.  In my case, this showed me all forwarders.
  3. Bring up Firebug command line and input the following code:
    var rows = $(“#mailtbl tbody tr”),
    returnString = “”;
    rows.each(function(i, item){
    var tdList = [];
    $(item).find(‘td.truncate’).each(function(s,subItem){
    tdList.push($(subItem).text());
    });
    returnString += tdList + “\n”;
    });
    console.log(returnString);
    This code may need tweaking for your cPanel version, but you should now see a list of the email forwarders you desire in the Firebug console.
  4. Create a new text document in the directory of your choosing.  Copy and paste the email addresses into the file and save as a csv.
  5. Create a new Excel spreadsheet with 2 columns and add the labels “From Address”, and “To Address”.
  6. On the data tab choose “From Text” under Get External Data.  Select the text (csv) file you just created and open.  Make sure you select Delimited and comma as the delimitation type.
  7. This will import the from address in the first column and to address in the second.
  8. All that is left is to click the Import Addresses/Forwarders link, upload the spreadsheet and follow the on-screen instructions.

That is it for migrating email addresses and forwarders over to new accounts.  It is not that complex, but maybe it will save you 20 minutes of your life someday.  Note that if your version of cPanel does not have jQuery installed, you can use FireQuery to inject it.

New Site Theme

You may notice that this blog has a new and fresh look today!  I am pleased to announce that after careful consideration, I have chosen to switch the theme up from modern-grunge, to spectrum.  I love the clean look this template provides and being slightly wider seems to make it easier to read, specially when code examples are involved.  Let me know what you think and a big thank you to Ignacio Ricci for designing this easy-to-read layout.

I was recently building a deployment and description site for an Adobe AIR application I am building for school.  Any site I turn in to Full Sail must have 100% validated HTML markup and CSS.  As long as the design is half way descent and the markup is clean, all is well.  In appeasing my need to use HTML5 because I am a cool kid, and bearing graceful degradation in mind, I was all jazzed up to use the much acclaimed HTML5 Boilerplate.

Paul Irish totally rocks so I was shocked when my incredibly simple HTML5 page with CSS3 did not validate.  Upon further investigation, I realized not only does the HTML5 Boilerplate site not validate, it has 92 errors and 4 warnings (as of December 6, 2011).  I guess I should be happy mine only has one error, but there are weird validation errors coming from that site, including the use of custom characters in the DOCTYPE declaration.  I concede that the validation I speak of is the W3C Validation Service, and that is not always necessarily 100% accurate, however the amount of errors is aPAULing…get it? Paul…appalling?  Sorry, terrible sense of humor took over.

Image

Anyway, I am curious if anyone else has ran into issues with the HTML5 Boilerplate not validating and if so, is there any other alternatives out there that give us the HTML5 goodness we as web developers so eagerly crave.

It is with great sadness I am announcing the immediate availability of the purchase of our families motohorhome.  We absolutely love and adore this thing and treasure all of the memories we have made with it.  We put a ton of blood, sweat, tears (literally), and money into this thing, so it really feels like a home away from home.  First let us have a glance at some not so professional pics.  There is no mechanical or serious functional issues with this unit that I know of.

Asking $23,999 $22,999

The unit books for over $26,000 on NADA: 1997 Holiday Rambler VACATIONER Series M-36SGS FORD – 36′(VACATIONER,MH,Queen Bed,1) Standard Equipment, Prices & Specs Window Sticker – NADAguides

Email me for more information: zachariahtimothy [at] gmail.com

This slideshow requires JavaScript.

Next some textual information;

Features we love about this bad boy:

  • Space, space, space – There is an abundance of space and storage throughout the whole unit.  We filled it with everything you could ever want camping, and still had extra space.  The slideout contains the kitchen and couch so it feels like a small apartment.
  • Sleeping room – This unit sleeps up to 8 people as far as beds are concerned.  With a couple kids, the bunk beds in the back come in really handy for nap time so they are not disturbed.  The bed is a queen size with a brand new mattress.
  • Large shower – Being 6’2″ makes a guy learn to appreciate a large shower.  The hand held shower head makes it easy to conserve water too.
  • Movies – We are huge movie buffs and this thing is wired for multiple televisions, DVD/Blu-Ray player, and in-motion satellite system.  There is speakers throughout so you get the full surround sound experience.
  • Dual air conditioners – Keeps plenty cool in the heat of the summer.
  • Backup camera – People wonder how I back this beast into smaller spots, and it is because of the clear backup camera complete with night mode and sound.
  • Awning – The main awning is in good shape and the window awning add extra privacy and cooling in the summer.
  • Comfort – Overall we were just extremely comfortable in this thing.  It is open and cozy with a home away from home feel.
  • Exterior Design – Aerodynamic shape so it is not like driving a giant box down the road.

Features that are not so loved (honesty is the best policy):

  • Gas Motor – The Ford 460 is underpowered for this unit. It gets us anywhere in the mountains we can go, but not doing 90 in the passing lane :) .
  • Age – Hey it is from 1997 so there is some maintenance and upkeep as with ANY RV.  We took the brunt of the original repairs so there is nothing but very small repairs left.

Just the facts:

  • 1997 36 foot Holiday Rambler Vacationeer Motorhome on Ford F-53 Chassis.
  • Only 65,000 miles. The previous owner lived in it.
  • Air-Lift air ride suspension.
  • Mor/Ryde suspension with tag axle.
  • HWH hydraulic leveling system that is electronically controlled from the comfort of the driver seat.
  • Large “superslide” electric slideout.
  • Large awning, 2 bedroom window awnings.
  • In-Motion Winegard Movin-View satellite system.
  • Dual ducted 13,500 BTU Dometic air conditioners.
  • Newly rebuilt transmission with upgraded extra gear.  The shifting on this thing is incredible, especially in the mountains.
  • New radiator.
  • New custom exhaust with Lifetime warranty Aero muffler.
  • New board on water heater.
  • New queen size mattress from Denver Mattress.
  • Nearly new Onan Marquis 5500 watt generator (super quiet).
  • Water station in basement for waste cleanup, and outside spigot.
  • Dometic Elite refrigerator.
  • Fan-tastic fan (lifetime warranty) with thermostat control.
  • Pass-through basement storage with lighted compartments.
  • Double electric lit step.
  • Dinette and couch fold into beds.
  • Seat-belts to legally seat 7 peeps.

There are several approaches to organizing code in any application.  With the Model View Controller (MVC) pattern, much of the code is organized for you by convention alone, specially if you are using ASP.Net MVC.

In an effort to follow the conventions and patters set forth by MVC, I started thinking about how to pull the JavaScript out of my views, that is, I want my JS code organized in a pattern satisfactory with the file structure of MVC.  One thing I love about MVC, is that when I look at a controller, I know almost exactly where to look to find the view, and vice versa.  The Solution Explorer screenshot shows my take on how to organize JS code in such a matter.

JS Namespace and Class Setup

The App.js initializes the namespacing and classing that will be used to organize the client-side, and more importantly prevents that pesky global namespace from becoming cluttered.  It sounds pretty hard core talking about namespacing and classing on the client-side right?  It is.  It is highly technical and complex to….ok well maybe it is just a series of objects, that looks and feels like C#’s namespacing/classing at runtime. Note that this is accessed using the dot notation (MYAPPLICATION.App.Ajax.PostForm();).  In this case I split the “App” code away from the “View” code.

 I chose to do this simply because that is how the C# project namespacing was setup in the project structure.

The Ajax, Form, and Utilities classes are just infrastructure code that I use to post forms, create pdf’s, override default behavior using prototype, setup default jQuery UI functionality, etc.  Read more about submitting MVC forms using jQuery if you dare.

MYAPPLICATION.Views{} is simply an object that allows me to organize my JS code similar to how the views are generated.  There are two advantages I have found that instantly save me time; 1) I can look at a view in the VS Solution Explorer and know exactly where to find the associated JS, and 2) I can look at a url route and know exactly where the JS for that page lives.   Another big benefit is it helps keep the JS out of the view.  This leaves only 1 line of code in the view itself, which is required to instantiate the JS for said view:

<script>
    MYAPPLICATION.Views.History.Index.Init({ orderDetailGridUrl: '@Url.Action("OrderDetailGrid", "History", null)' });
</script>

Note that if you use Firebug (which you should be), it makes debugging a bunch easier as well because you can select the appropriate script file (which Firebug organizes by Controller thanks to our file structure) versus scrolling through the markup on the script tab and trying to find the right line, YUCK.

 Then all the History code lives in one file, and is loaded after the MYAPPLICATION.App{} code so it can utilize all utilities and ajax goodness already written.

MYAPPLICATION.Views.History = {
    Index: {
        Init: function (options) {
            // History index page code goes here...

        }, ///end Index.Init()
    }
};

So far there have been no drawbacks to this approach because you can still use other JS patterns that work well with this setup.  I have used the JS module pattern in other applications and instantiated them the same way as shown here.

Quote for Today

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code (p15), 1999

I just downloaded a new version of Windows Server 2008 R2 64-bit and to my dismay, Dreamspark shells the image out as a .img file instead of the typical and beloved .iso. I looked online to find out what the heck to do with the .img file and found a bunch of sites explaining how to run a command line program (VBoxManage) to convert the .img into a .vdi.  The conversion went well but the .vdi did not work when I tried to mount and start the VM to boot to it.

To my delight, I then tried renaming the .img to have an extension of .iso and SNAP!  It works.  Mounted up the .iso in typical fashion and Server 2008 is now running on my MacBook Pro.  I understand Ubuntu is handing out .img files instead of .iso as well.  Must be some better compression value or the like (the Server 2008 R2 Standard/Enterprise/Web/Datacenter all in one was only 3GB).

Great Quote

The right place to put any given unit of code is where it provides the most value and reliability with the least cost and load on the system.
-David Wendelken

Saw this in a forum post, and thought it was a great quote.

MVC3′s model binding support is fantastic! The software our team develops is search/results based so staying on a single page to display a grid is important. There are many jQuery based element serializers, but I wrote my own because I wanted something extremely basic and simple and hey, why not since it is so easy! Before we look at the serializer, let’s look at how we use jQuery to submit our form so the Post does not render a new page.

jQuery Form Post (link to code example)

Now that we bound our function to the form submit event, we can serialize our form. The serializer function is very basic but works great. It uses the jquery data() to include stored data to bind to the model. This can be really handy for non-form elements and custom client-side functionality. Basically any information you want to head back to the server, just add like so:

$("#myForm").data("ToPost", { SelectedGridIds: [1, 14, 922] });

The serializer function will automatically add the “ToPost” data objects to the JSON object to be returned to the server.

jQuery Form Serializer (link to code example)

Now my Post function has stopped default event propagation, and serialized the data I need, now we just need to post it. You can use your favorite ajax post method, but I prefer to use the wrapper function I created. It uses jQuery do make the actual post (which I also prefer).

Implementation:

First, we need a quick little jQuery plugin to manage all our “Form” operations:
//Creates a jQuery accessor for NRPC.Form object.
//Example: $('form').Form('Post', {options});
// Decorate each class with the jQuery self-executing function to prevent IE from blowing up in debug mode.
(function ($) { 

$.fn.Form = function (method) {
if (MyNamespace.Form[method]) {
return MyNamespace.Form[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return MyNamespace.Form.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on MyNamespace.Form');
}
};

})(jQuery);

Sweet, now when the page loads, all we have to do is register the form post with $(“form”).Form(‘Post’);.

Here is a real-world implementation:

$("form#Search").Form('Post', {
targetId: 'divGrid',
onAjaxSuccess: function (resultGridHtml) {
var gridResult = $(resultGridHtml)[0];
$("#divGrid").html(gridResult);
}
});
Follow

Get every new post delivered to your Inbox.