Coding Horror

programming and human factors

Coding Horror Stickers

As I alluded to in the T-Shirt post, Coding Horror stickers have arrived:

Coding Horror stickers

These are custom, two color die-cut vinyl stickers based on the high resolution vector art so graciously provided by our kind benefactor, Steve McConnell. To give you an idea of scale, the coin in the picture is a nickel. The dimensions of the sticker are 3.55" h × 3" w.

As a thank you to my readers, anyone who emails me from now until midnight PDT Wednesday, August 16th gets a free Coding Horror sticker. Please make the title of the email "free sticker", and don't forget to provide your full postal address. You must live in the US or Canada.*

Update: we've reached 350 stickers; the free sticker offer is now closed. I totally blame Mike Gunderloy. I'll try to get all the stickers out by Monday. I think you'll really like them!

United States
$4 for 4 stickers
International
$4 for 3 stickers

* Sorry, international readers. Dealing with postage rate scales makes my tiny American brain hurt.

Discussion

The Magical Number Seven Plus or Minus Two

The seminal 1956 George Miller paper The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information is a true classic. In it, Miller observed that the results of a number of 1950's era experiments in short-term memory had something in common: most people could only retain 5 to 9 items in their short-term memory.

This study is commonly cited as the reason why Bell chose to make telephone numbers exactly 7 digits long. I can't find any formal citations to support this, but the timing is right: by 1957 or thereabouts, most telephone numbers in the US were standardized to the 7-digit format.

5551212

Are human beings only capable of holding between 5 and 9 pieces of information in their heads at once? That's only 2.5 bits of information. If you read the text of the paper, you'll quickly find that even Miller himself found the magic number seven a bit serendipitous:

And finally, what about the magical number seven? What about the seven wonders of the world, the seven seas, the seven deadly sins, the seven daughters of Atlas in the Pleiades, the seven ages of man, the seven levels of hell, the seven primary colors, the seven notes of the musical scale, and the seven days of the week? What about the seven-point rating scale, the seven categories for absolute judgment, the seven objects in the span of attention, and the seven digits in the span of immediate memory? For the present I propose to withhold judgment. Perhaps there is something deep and profound behind all these sevens, something just calling out for us to discover it. But I suspect that it is only a pernicious, Pythagorean coincidence.

The 7 digit figure might be a little optimistic. Other research has shown the number to be closer to 4. Even telephone numbers aren't commonly expressed as seven digits. They're expressed as a group of three digits and four digits, with a dash to separate them:

555-1212

And the area code is separated, too:

434-555-1212

So which is it? Can people remember 7 digits at once? Or are they really remembering chunks of 3 digits, 3 digits, and 4 digits?

I think magical numbers are a red herring. There are some interesting coincidences, however, such as Edward Hall's conclusion that the perfect group size is 8-12 people:

Fortunately, something is known both empirically and scientifically about the influence exerted by size on groups and the effect of size on how the groups perform. Research with business groups, athletic teams, and even armies around the world has revealed there is an ideal size for a working group. This ideal size is between eight and twelve individuals. This is natural, because man evolved as a primate while living in small groups…Eight to 12 persons can know each other well enough to maximize their talents. In groups beyond this size, the possible combinations of communication between individuals get too complex to handle; people are lumped into categories and begin the process of ceasing to exist as individuals. Tasks than can't be handled by a group of eight to 12 are probably too complex and should be broken down further. Participation and commitment fall off in larger groups -- mobility suffers; leadership doesn't develop naturally but is manipulative and political.

The value of this magical number lies in knowing the point of diminishing returns. Every group should strive to be as small as possible. Once the group size exceeds 8-12 people, break into another group.

Similar advice applies to software design. Ideally users shouldn't have to remember anything. Once they have to remember more than 7 items, it's definitely time to redesign.

  • In a well-designed system, you should never need to fall back on your faulty, unreliable short-term memory.
  • The fewer bits of information users have to remember, the better.
  • Use chunking and grouping aggressively to reduce the amount of information to remember.

Magical numbers are fun. But the ideal group size is always one, and the ideal number of things I should need to keep in my short-term memory is zero.

Discussion

Sometimes It's a Hardware Problem

One of our best servers at work was inherited from a previous engagement for x64 testing: it's a dual Opteron 250 with 8 gigabytes of RAM. Even after a year of service, those are still decent specs. And it has a nice upgrade path, too: the Tyan Thunder K8W motherboard it's based on supports up to 16 gigabytes of memory, and the latest dual core Opterons.

Anyway, we have it set up for Virtual Server 2005 R2 duties, running Windows Server 2003 x64. However, there was some anomalous behavior:

  • Virtual Server reported weird error messages: "Some nodes of this machine do not have local memory. This can cause virtual machines to run with degraded performance".
  • The machine spontaneously rebooted during the day and overnight.

We've used this server for over a year and never experienced anything problematic with it. The weirdness only started with the server's new role.

The first thing we did was update the BIOS to the latest version, and make sure we had all the latest x64 chipset and platform drivers installed. This is always a good first troubleshooting step-- it's the hardware equivalent of taking two asprins and calling in the morning. This resolved the "some nodes of this machine do not have local memory" error. However, the machine still spontaneously rebooted overnight, even with the latest BIOS and drivers.

At this point I began to suspect a hardware problem. Troubleshooting hardware stability can be difficult. But you can troubleshoot hardware stability quite effectively with the right software: Memtest86+ and Prime95.

  1. Testing memory stability with Memtest86+

    We started with Memtest86+ because we already suspected the memory. Memtest86+ isn't the only memory testing diagnostic out there, but it's probably the most well-known. Microsoft also offers their Windows Memory Diagnostic utility, which works exactly the same way. Memtest86+ is available in several forms from the Memtest86+ web site. We chose the ISO image, which we burned to CD. Boot from the Memtest86 CD, and it'll kick off the test run.

    A Memtest86+ screenshot

    It took about 30-45 minutes to test 4 gigabytes of memory. The progress bar at the top right gives you an indication of how long the test has to run; there are 8 total tests in the standard test run. Beware, because it'll start repeating at test #1 after the first pass!

  2. Testing CPU stability with Prime95

    Prime95 is my single favorite PC stability testing tool. If your PC can't pass an overight Prime95 run, it absolutely, positively has a hardware problem.* Although Prime95 is primarily a CPU test, it can also be a pretty good memory test, too. After downloading it, go to the Options menu and select Torture Test.

    1. If you want to test CPU stability exclusively, choose "Small FFTs".
    2. If you want to test for CPU stability and memory stability, choose "Blend".

    If you have a Dual (or Quad) CPU machine, you must run multiple instances of Prime95 to load each CPU. The easiest way to do this is to copy the Prime95 folder and run multiple executables, each one from a unique folder. You may want to set CPU affinity on the executables with Task Manager, but the scheduler will take care of loading all the CPUs just fine by itself.

    A bit of warning, though: when Prime95 says "lots of RAM tested", they mean it. We tried running two instances of "Blend" with only 4 gigabytes of memory installed on the server and we nearly crushed the pagefile; both instances allocated nearly 6 gigabytes!

    Prime95 torture test dialog

    In my experience, Prime95 will error out almost immediately if your CPUs or memory are unstable. This is great for troubleshooting because you know quickly if there's a problem or not. If you can run Prime95 "small FFTs" for an hour, it's highly likely that the CPU isn't your problem. And if you can run the same test overnight, CPU problems can be definitively ruled out.

In the case of our wayward server, Memtest86+ showed us rare, intermittent memory problems. But Prime95 consistently failed almost immediately when running the "blend" test. When we switched Prime95 to "small FFTs", it ran two instances for an hour just fine. Clearly a memory issue! Using a combination of Memtest86+ and Prime95, we found that our server was totally stable with 4 gigabytes of memory installed; the minute we put in all 8 gigabytes, we couldn't pass one or both tests.

Since 8 gigabytes of memory is essential for a VM server, removing memory wasn't an option. On a hunch, I switched the memory speed from 200 MHz to 166 MHz in the BIOS. Now both Prime95 blend and Memtest86+ pass without incident.

Although software is notoriously unreliable, we can't always blame the software. Sometimes you really do have a hardware problem.

* CPUs are almost never defective; it's usually a heat or power supply related failure.

Discussion

The Last Configuration Section Handler.. Revisited

If you need to store a little bit of state-- in your configuration file, or on disk-- nothing is faster than some quick and dirty serialization. Or as I like to call it, stringization.

In late 2004, I wrote about The Last Configuration Section Handler, which does exactly this for *.config files. It's based on earlier work by Craig Andera of Pluralsight. Let's bring that code up to date for Visual Studio 2005, and furthermore, we'll do it in C# and The Language of the Gods, VB.NET.

The first thing to do is set up a little class that represents the data you want to serialize. Include whatever types you need, but make everything public so it'll be visible to the serializer.

namespace SomeNamespace
{
    
public class MyStuff
    {
        
public int i;
        
public string s;
    }
}

Now use this routine to serialize it:

static string SerializeObject(object o)
{
    
StringBuilder sb = new StringBuilder();
    
StringWriter sw = new StringWriter(sb);
    
XmlTextWriter xtw = new XmlTextWriter(sw);
    
xtw.Formatting = Formatting.Indented;
    
xtw.WriteRaw(null);

    
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
    
xsn.Add("", "");

    
XmlSerializer xs = new XmlSerializer(o.GetType());
    
xs.Serialize(xtw, o, xsn);
    
string s = sb.ToString();

    
// <Foo> becomes <Foo type="MyClass.Foo">
    s = Regex.Replace(s, "(<" + o.GetType().Name + ")(>)", "$1 type="" + o.GetType().FullName + ""$2");
    
return s;
}

The output is your class, serialized as a nice human-readable string.

<MyStuff type="SomeNamespace.MyStuff">
  <
i>1234</i>
  <
s>A bunch of information</s>
</
MyStuff>

It's just so darn.. straightforward. As if I needed another reason to love strings. Anyway, take that string and paste it into your web.config file.

To read it in, you'll need a custom config section. Paste this into your config file to define one:

<configSections>
  <
section name="MyStuff" type="XmlSerializerSectionHandler, CSSerializerSection" />
</
configSections>

The actual XmlSerializerSectionHandler is a bit too much code to paste into a blog post, but it's still relatively simple:

  1. Extract the type from the XML Type attribute
  2. Make sure the type is valid
  3. Deserialize the XML into a new object of that type

The XmlSerializerSectionHandler is too verbose to reprint here mainly because I added a bunch of error trapping. If something goes wrong, you get a nice explanatory exception instead of a cryptic error. It's good stuff.

There's almost no difference at all between the two languages, except that VB for some reason requires an additional namespace; instead of "SomeNamespace.MyStuff", it's "VBSerializerSection.SomeNamespace.MyStuff".

Discussion

Fitts' Law and Infinite Width

Fitts' Law is arguably the most important formula in the field of human-computer interaction. It's..

Time = a + b log2 ( D / S + 1 )

.. where D is the distance from the starting point of the cursor, and S is the width of the target. This is all considered on a 2D plane relative to the axis of movement.

Fitts' Law diagram

Years of experimental results have proven Fitts' law time and time again:

Fitts' law has been shown to apply under a variety of conditions, with many different limbs (hands, feet, head-mounted sights, eye gaze), manipulanda (input devices), physical environments (including underwater!), and user populations (young, old, mentally retarded, and drugged participants). Note that the constants a and b have different values under each of these conditions.

It's not exactly rocket science, as Bruce Tognazzini points out:

The time to acquire a target is a function of the distance to and size of the target.

While at first glance, this law might seem patently obvious, it is one of the most ignored principles in design. Fitts' law (properly, but rarely, spelled "Fitts' Law") dictates the Macintosh pull-down menu acquisition should be approximately five times faster than Windows menu acquisition, and this is proven out.

So, to make navigation easier, you either put clickable items closer together, or you make the clickable area bigger. Or both. I know what you're thinking: no duh. But bear with me.

Here's one thing that puzzled me. I hate Windows as much as the next disestablishmentarianist, but how can the menu argument be valid? Are Macintosh pull-down menus really that much larger than Windows pull-down menus?

Fitts' Law for Windows Notepad pull-down menus

They aren't significantly larger. But Macintosh menus aren't attached to the application window-- they're always at the top of the screen.

Fitts' Law for Macintosh menus

Since the cursor stops at the edge of the screen, for the purposes of Fitts' law calculation, Macintosh menus are infinitely tall! Thus, Macintosh menus are faster to navigate.

Although placing the menus at the top of the display does leverage Fitts' law nicely, it also presents its own set of problems.

  • Where does the menu go in a multiple monitor scenario? I use three monitors on both my home and work PCs. If I move an application to the rightmost monitor, do the application menus still appear on the center or left monitor?
  • Detaching applications from their UI in this manner seems to violate the rule of proximity-- related things should be together. On a single monitor system, the distance between the application and its menu could be quite large unless the application window is maximized.
  • In a broader sense, I think the days of the main menu are numbered as a keystone GUI metaphor. As far back as I can remember, the Macintosh has always used this "menu at the top of the display" metaphor, so it's written in stone for users at this point. Change could be painful. But then again, Apple has a habit of reinventing themselves periodically, so who knows.

Fitts' law isn't just about making things larger and easier to click on. It's about maximizing the utility of the natural borders on the edges of your screen:

Fitts' law indicates that the most quickly accessed targets on any computer display are the four corners of the screen, because of their pinning action, and yet, for years, they seemed to be avoided at all costs by designers.

Use the pinning actions of the sides, bottom, top, and corners of your display: A single-row toolbar with tool icons that "bleed" into the edges of the display will be many times faster than a double row of icons with a carefully-applied one-pixel non-clickable edge between the tools and the side of the display.

I've definitely felt the pain of Fitts' law violations.

I love multiple monitors. In my opinion, life begins with two displays, the largest you can afford. And you should really upsize to three if you want maximum benefit. But one unfortunate side-effect of multiple monitors is the removal of some natural edges between adjoining monitors. The cursor now flows freely between monitors; it's painful to stop the cursor on the left and right edges of the app on the center monitor.

And Fitts' law violations can also extend to hardware. Consider touchpad designs that have dedicated scrolling areas on the left or bottom.

Fitts' Law violating touchpad

This seems like a good idea on paper, but in practice, it destroys the usability of the touchpad. On a touchpad with dedicated scrolling areas, you have no way to know when you've passed from touchpad area into the no-man's-land of scrolling area. The natural edges of the touchpad are ruined; we've given them an arbitrarily different, hard-coded set of functionality. Dedicated hardware isn't even necessary to achieve scrolling effects on a touchpad. We can easily leverage Fitts' Law in the touchpad driver software instead. Just slide your finger until you hit an edge, then slide it along the edge.

The edges could be your most valuable real estate. Use them responsibly. Fitts' law is powerful stuff.

Discussion