Usability in Everyday Life

As software engineers (especially ones who work on forward-facing user interfaces), we are taught to think about usability. Many of us are not good at it - including me (though I’m making a conscious effort to get better about it and “think more like a user”). Large companies, on the whole, have mastered this because they can expend huge amounts of money on research and focus groups to study what people want and how they interact with their software. Apple is a master at this. And, this is why the GIMP is terrible to use when compared to Adobe Photoshop. Oh, sure, the program itself is perfectly capable, but the interface was clearly designed by an engineer and not a graphic designer.

The other approach is, of course, to separate the engineers from the UI design people. In a company the size of Apple or Adobe, I’m sure this is probably what they do. But small to midsize companies simply can’t afford to do that and, even if they could, somewhere along the line some engineer has to interface with the front end code.

But thinking about the “user experience” is not just related to programming - any industry that has to deal with people who are not native or fluent with that industry can benefit from trying to “think more like them.”

The hotel I’m staying in for OSCON here in Portland, the Doubletree, is a good example of this. When you exit the elevator on the fifth floor, there is the standard sign that rooms 500-520 are to the right, and 521-541 are to the left. The room numbers are not on the doors - they are on small plaques next to each door. But, the plaques don’t uniformally face the hallway or face in a uniform direction - some face the way you are walking from the elevator and some, strangely, face the opposite direction so that they will never be seen unless someone is walking from the opposite direction as they would normally walk when looking for a room.

Think about this for just a second. The time when those plaques are needed the most is when someone is first finding their room, and they will almost always be coming from the elevator. After that, you usually remember, generally, where it is. In order to see half of the signs on the floor, you have to turn around and look behind you as you are walking.

To add to this, think about how you would normally look for a room in a hotel. Do you go all the way to the end of the hallway? No - you probably stop about 10-15 feet from the end if you determine that your room is not one of the remaining ones. So unless you are paying careful attention to the plaques on the wall, there is a chance that you will not ever see your room. This is the reason I spent ten minutes walking up and down the hall trying to find my room: it was at the very end of the hall with a plaque that was only visible if you were walking the opposite direction.

Now, it’s not like this breaks my entire world. I found my room, put my stuff down, and went out for a beer. But when looked at through the lens of usability, which software engineers are very familiar with, it could certainly use improvement. I’m sure the design makes perfect sense to the building architect and to all the people who work in the hotel. But to a guest, it makes little sense and requires extra time spent looking for their room.

Search Engine Friendly URLs with mod_rewrite

By now, I’m sure we all know about search engine friendly (SEF) URLs - that is, URLs that are able to be traversed by a search spider. Spiders don’t like to see a bunch of stuff on the query string (file.html?blah=foo), but do like standard URL patterns like /file/foo.html. Not to mention that it’s a lot easier to read. But what happens when you need to do something more complicated - say, rewrite using different types of conditions with optional arguments?

Say, for instance, I have a script that takes arguments like this:

/file.php?id=1[&view=1]

And I want to rewrite it to look like this

/file/(id).html[&view=1]

In this case, the view argument is optional and could relate to any number of unique cases, such as internal viewing or refcode tracking, for instance. Well, your first thought might be something like this:

RewriteCond %{REQUEST_URI} ^\file\/\d+\.html [OR]
RewriteCond %{REQUEST_URI} ^\/file\/\d+\.html(.*)
RewriteRule ^\/file\/(\d+)\.html(.*) /file.php?id=$1&$2 [L]`

But it doesn’t work. This is because the query string isn’t part of the URI available for the rule to match. But, mod_rewrite, being the cool Swiss Army knife it is, lets you get around this by back referencing to the condition. Using the % operator instead of the $ allows you to reference parentesized expressions in the condition, like so:

RewriteCond %{REQUEST_URI} ^\/file\/\d+\.html
RewriteCond %{QUERY_STRING} (.+)
RewriteRule ^\/file\/(\d+)\.html?(.*) /file/file.php?id=$1&%1 [L]

RewriteCond %{REQUEST_URI} ^\/file\/\d+\.html
RewriteRule ^\/file\/(\d+)\.html /file/file.php?id=$1 [L]`

It’s described here in the docs. I thought this was a pretty cool solution to a problem that had been vexing me.

Diffing files via FTP

I ran into a situation today where I needed to diff files on a remote server against the ones on a local server when the only connection method I had to connect to the remote server was FTP. I wrote a little quick and dirty script to diff files over FTP. It’s stupid simple - it downloads the file and runs diff on it against a local file, outputting the result.

It’s great for finding changes on a webhost that cripples real developers by only offering FTP. It’s also a great companion to ftpsync, which apes some of the functionality of rsync, again on crippled webhosts.

The command format is:

ftpdiff <local file> <username:[email protected]:/path/to/file>

Security on Shared Hosts

Shared hosts are a reality for many small businesses or businesses that aren’t oriented around moving massive amounts of data. This is a given - we can’t all afford racks full of dedicated servers. With that in mind, I would urge people to be more careful about what they do on shared hosting accounts. You should assume that anything you do is being watched.

Take, for example, the /tmp directory. I was doing some work for a friend this weekend whose account is housed on the servers of a certain very large hosting company. While tweaking some of his scripts, I noticed via phpinfo() that sessions were file-based and were being stored in /tmp. This made me curious as to whether any of that session data could possibly be available for public viewing.

My first move was to simply try FTP’ing up and CD’ing to /tmp directory. No go - they have the FTP accounts chrooted into a jail, so the obvious door is closed. However, the accounts have PHP installed, so I can do something like this in a PHP script:

<?php
system("ls -al /tmp");
?>

With this little bit of code, I can look into the tmp directory even if my FTP login is chrooted. Fortunately, sessions on this host are 600, so they’re not publically readable -  this was my primary concern and the reason I took some time to check this out. But people are putting lots of things into the tmp directory with the misguided idea that it is their private temporary file dump, including one idiot who put a month’s worth of PayPal transaction data into tmp and left it 644 so that it was publically viewable.

Now, I’m a nice guy and the only thing I’m going to do with this information is laugh at it. But keeping in mind how dirt cheap hosting accounts are, there’s not a high entry barrier for someone with fewer scruples.

The key thing to remember is that, if you need temporary file storage on a shared host, do it someplace less obvious, set the permissions so that only you can read/write to it (600), and clean up by deleting files as soon as you possibly can.

Facebook Errors

    My Facebook news feed hasn’t update since May 15th - a span of four days, in which I know many of my friends have posted or at the very least updated their status.

    With 50-something friends, I know for sure some of my friends are updating - my feed just isn’t reflecting it. So, after Googling about (Facebook’s site, for the record, is extremely unclear about contacting the company and/or reporting bugs), I found this:

    Great! A place to file a report. So I type in my report and submit …

    D’oh. Apparently, I’m not the only one having this issue, either. C’mon guys, get it together! At least let us users know what’s going on.

    Installing PECL PS on Mac OS X

    The PHP that comes standard with Mac OS X Leopard doesn’t come with the PECL PS extension. PECL PS requires pslib, and the last version I verified to work the PS extension was 0.2.6 (I still have an outstanding bug for that). There’s a minor little bug that prevents it from compiling on OS X, so here are the steps necessary to get PECL PS working on Leopard:

    1. Download PSLib 0.2.6. Unpack to somewhere on your filesystem (I use /usr/src)

    2. cd pslib-0.2.6/src

    3. Apply this patch to pslib.c (patch pslib.c leopard_pslib-0.2.6.patch)

    4. cd ../

    5. ./configure

    6. make

    7. make install

    By default this puts it in /usr/local/lib. Now install the PS extension using PECL.

    1. pecl install ps

    2. When it asks for path to pslib installation, /usr/local/lib

    3. Once it’s done compiling, add the .so to your php.ini. You may have to move the .so or alter extension_dir in your php.ini.

    4. sudo apachectl restart

    ngrep and memcache

    You can use the Linux command ngrep to “watch” what is going into and coming out of memcache. ngrep is an amazingly useful tool for troubleshooting a wide array of network issues; I previously have used it extensively for troubleshooting SIP errors. In this case, I’m using it to be sure memache sessions in PHP are actually working.

    codelemur ~ # ngrep -d lo port 11211
    interface: lo (127.0.0.0/255.0.0.0)
    filter: (ip) and ( port 11211 )
    ####
    T 127.0.0.1:60912 -> 127.0.0.1:11211 [AP]
    get a804f5517468d4696c60da7eaf8a7179..
    ##
    T 127.0.0.1:11211 -> 127.0.0.1:60912 [AP]
    VALUE a804f5517468d4696c60da7eaf8a7179 0 16..test|s:4:"test";..END..
    ##
    T 127.0.0.1:60912 -> 127.0.0.1:11211 [AP]
    set a804f5517468d4696c60da7eaf8a7179 0 1440 16..test|s:4:"test";..
    #
    T 127.0.0.1:11211 -> 127.0.0.1:60912 [AP]
    STORED..

    It doesn’t help too much if you have multiple memcache servers (which is kinda the point of memcache), and since it’s raw data you can’t inspect the packets if they’re compressed, but in a testing environment, it’s a great way to be sure all things are kosher.

    Ubuntu 8.04: My Thoughts

    Every so often I get the urge to check out desktop Linux - just to see how things have progressed and whether or not it is in a usable state yet. For the last few times, the distro of choice I have tried has been Ubuntu, as that seems to be the new de facto starting point for a desktop distro.

    Before beginning this review, let me first say that desktop distros have come a long way over the last few years, and Ubuntu is by far the most usable of the ones I’ve seen. Ubuntu itself has come a long way and, for someone who is willing to compromise on some points, is quite usable for someone who’s willing to spend some time tweaking things.

    Having said that, it still has a ways to go before reaching Windows. And it’s not even in the same league as Mac OS X.

    First, a little about my test rig: An AMD Athlon64 3700+ with 2 gigabytes of memory, two 250gb SATA hard drives (one for Windows, one for whatever OS I’m testing at the time), and dual GeForce 7600 GS’s running three 19” Samsung LCDs. Not your standard setup, mind you, but not ultra advanced and bleeding edge, either.

    The installation: The installation is much the same as previous releases of Ubuntu: load up the live CD and, from within the live environment, launch the installer. The installer itself asks fewer questions that the Windows XP installer, yet seems to be able to do more. And doesn’t require endless reboots to get everything working.

    My installation proceeded mostly okay (being that Windows resides on sda, I installed Ubuntu in sdb), except that after I installed and rebooted … nothing. It kept booting into Windows. I reinstalled again just to be sure I didn’t blitz through the boot record screen, but sure enough, writing to the MBR on sda doesn’t work when you have two SATA drives and you’re installing Ubuntu on sdb. This has been a bug for at least the last two times I’ve tried to install Ubuntu. I can fix it with grub commands and properly write a boot record to sda, but for the purposes of testing (and because I’m lazy and wanted to play with it) I just plugged sdb directly in and removed sda. So I’m up and running. This is something that would befuddle a lot of folks, but to be fair I’ve had problems with Windows in the past, but it seems like it would be an easy fix.

    So I have Ubuntu installed now. Yay. Next step is to get my three LCDs working. This is where we run into what I think is the biggest hinderance to desktop Linux: X.

    If I plug three monitors into two video cards on a Mac, it’s going to turn on all three monitors and allow me to drag things between them all effortlessly (one big desktop). If I plug it into Windows, I’ll need to download the drivers, but after that, no problems. Not so in X, though in fairness it is likely more due to the intrangisence of Nvidia when it comes to providing open source support.

    First, if you want to do anthing, you have to download a “Restricted” driver. This is Ubuntu-speak for “we didn’t want to compromise our oh-so-precious ‘freeprinciples in the name of usability” (in case you can’t tell, I have very little patience for zealotry). In Ubuntu 8.04, the Restricted Drivers Manager has been poorly renamed to Hardware Drivers. Doesn’t make a lot of sense, since a driver for hardware may or may not be restricted. So, I download and install the Nvidia drivers.

    Next, fire up the nvidia-settings utility to fix the X config. I was running this from the shell, but I later discovered that it puts a nice menu item in the Administration for you. It sees all my cards and, using this, I am able to configure everything up.

    You have multiple options for ways to do three monitors, but only one works: Xinerama. You could do three separate X screens, but you can’t move windows between them. You could do Twinview on one screen and a separate X screen but, again, you couldn’t move windows between a dual screen and the third monitor, the windows on the Twinview screen don’t maximize and minimize properly, and the login screen is right in the middle of the two monitors so that it’s very difficult to see what you’re tying when you login. Only Xinerama lets you move windows between the three monitors, allows them to maximize properly, and has the login on a single screen. This was about an hour of changing settings and restarting X before I got it right.

    The downside? It still isn’t supported in Compiz, which is a real bummer becauase compositing window managers was one of the things I was really looking forward to using. Anybody know if Compiz accepts bounties, because I really want this feature?

    So no Compiz. Oh well. Next, get my other hardware working. I have a Logitech MX1000 Laser (greatest mouse ever, by the way), and I like to map the buttons to do various things (most notably, I use the “cruise” buttons to go back and fourth on web pages). In order to get this to work:

    1. sudo apt-get install xserver-xorg-input-evdev
    2. cat /proc/bus/input/devices (find Logitech USB Receiver)
    3. sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.bak
    4. sudo gedit /etc/X11/xorg.conf
    5. Changes:
    Section "InputDevice"
    Identifier "Configured Mouse"
    Driver "evdev"
    Option "CorePointer"
    Option "Name" "Logitech USB Receiver" #this should be the name of the device which I made bold here.
    EndSection
    1. sudo apt-get install xvkbd xbindkeys
    2. gedit ~/.xbindkeysrc
    3. Changes:
    /usr/bin/xvkbd -xsendevent -text "\[Alt_L]\[Left]" m:0x0 + b:12
    /usr/bin/xvkbd -xsendevent -text "\[Alt_L]\[Right]" m:0x0 + b:11

    After restarting (yes, again) I have working buttons. Yay.

    The volume control on my Microsoft Natural Egro 4000 works now. It seems like this required some hacking last time around. Yay.

    Now to install some developer tools so I can get to work. I love Synaptic; I wish Mac OS X had real package management the way Linux does - it’s one of the things Linux really has going for it, though I generally prefer Gentoo’s portage manager. So I install Eclipse. Huge package, and I was getting really crappy download speeds, so I let it run all night and went to bed. The next day found Eclipse installed and ready to go. Installed PHP, SVN, Apache. So I now have the tools to work.

    My conclusions: I like Linux. I really do. I want to see Linux succeed on the desktop. And Ubuntu has gone further, faster than any other Linux distro. It is now by far the most fit and ready to use of any desktop Linux distro. I have a usable system now, and, theoretically, there is nothing stopping me from using my machine for most of my daily work.

    Having said that, there is a lot to be said for style. First of all, it’s ugly as sin. The Gnome UI, while it is much improved, is still terrible when compared to Windows and OS X. Also, who thought that brown was a good color for a UI? Second, the names of some of the tools are un-intuitive: “Hardware Drivers,” “SCIM Input Method Detection,” “Authorizations,” and others need to have more intuitive names, and once you use any of them, the layout is not really intuitive either. The initial screen layout with a menu at the top and a taskbar at the bottom is also not really all that usable, though it can be corrected by removing the top panel.

    I’m using it now (typing this in Drivel) so it is usable, but it still can’t displace my Mac for ease of use.

    Automatically Joining a Group Chat with Adium

    At dealnews, we have an internal Jabber server that we use for our internal communications. As part of that, we have a number of internal chat rooms for the various areas of the company.

    I’m a big believer in automation - that is, scripting various repetitive actions that I have to do every so often. One of these little things is joining our developer chat channel each morning when I get to the office. Unfortunately, there’s no built in way in Adium to do this, nor does Adium expose native AppleScript commands to join group chat. It does for other functions, but group chat functionality is conspiciously absent, even though there’s a long standing feature request to implement this.

    So, we have to hack it. In this case, I used AppleScript to imitate keyboard input

    set CR to ASCII character of 13
    tell application "System Events"
    tell application "Adium" to activate
    keystroke "j" using {command down, shift down}
    keystroke "development"
    keystroke CR
    end tell

    So we have a script, but how to automate the launching of it?

    I mentioned MarcoPolo before. It has quickly become one of my favorite pieces of Mac software. In this case, I use MarcoPolo to launch the AppleScript (with a 10 second delay to allow time for Adium to start and connect to the Jabber service). You can launch AppleScripts using the osastart utility like so:

    /usr/bin/osastart /Users/codelemur/Scripts/DevChat_AutoJoin.scpt

    It sucks that it’s like this, and I wish they would expose a more native way to do this, but it does work.