Monday, February 8, 2010

How should web pages ask for your address?

Dustin Curtis asks rhetorically:

Why does every store make me enter my zip code? It's easy to get that from the USPS with my address/state.
He's right of course, but this raises the question: what's the best way to solicit someone's address? Should we just remove the zip code field from the standard address form?


We can do better
. For example, my country must be USA if my city is New York and my state is NY. Furthermore, I should be able to specify both my state and city with "New York City" (there aren't any other New York Cities in the US) -- or maybe just "nyc".

However, unlike inferring zip code from address and state (which always works), the heuristics described above may or may not work depending on the address. Also, there are probably other heuristics that I'm excluding (for example, could I leave off the "west" in the address? Not in this case, but maybe sometimes).

Hmmmm, if only there were some website that knew all these heuristics and could tell you with certainty whether any given string (e.g., "120 west 45th st, nyc") uniquely identifies a single address. If only this magical website had an API!

Given that we can use Google Maps to identify addresses for us, I think the optimal address form looks like this:


You enter your full address (just as you would into Google Maps), and the form offers you suggestions (by talking to Google Maps) as you type. This is exactly what I implemented on BombSheets.com (try entering your address in the "Billing address" field).

Here's how one would enter the same address in the form above (120 west 45th street, New York, NY 10036) into the billing address field on BombSheets:

(It's the first choice after typing only "120 west 45")

(And the only choice after typing "120 west 45, nyc")

What an easy and fun way to buy bed sheets online, right?

Of course, Google limits you to 15,000 geocode requests per day, so this exact solution wouldn't scale for a site like Amazon, but I still think the overall approach is the future.

Monday, December 7, 2009

What should a site do when you try to access a page that doesn't exist?

What happens when I try to visit Nick's Huffpo article about Rap Genius (http://www.huffingtonpost.com/nick-antosca/jay-zs-empire-state-of-mi_b_346636.html), but I get the URL wrong (say I try http://www.huffingtonpost.com/nick-antosca/jay-zs-empire-state-of-mi)?



This isn't a great solution:
  1. The lack of design clearly brands this as an "error page". This is visually unpleasant and it makes the user feel like he's done something wrong
  2. Why not show me the results of your suggested search query (the first of which is the article I want) on the "page not found" page itself, rather than making me click "Google Search" first?
Your site's 404 page should be functionally identical to its search page, with the search query constructed intelligently from the URL.

Here's Huffpo's search page:


Why not throw this on the 404 page?

This is what we do on Rap Genius. For example, if you try visiting http://rapgenius.com/cam/get/em you'll see:


Better still, if your search only has one result (e.g., you tried http://rapgenius.com/cam/get/em/daddy) we take you directly to it and you don't see the "Something isn't right" page at all.

This approach has the added benefit of making it easy to visit a specific song. For example, if I want to go to Jadakiss' "Why", I can just type "http://rapgenius.com/jada why" in my address bar.

There was once a time when a URL had to correspond to an actual file on a computer somewhere*. Fortunately this is no longer the case. Therefore, web designers should stop building applications that interpret user requests for URLs as requests for specific documents and instead as requests for the web application to "do the right thing".

* This is why you still see so many URLs that end in ".html". URLs should never end in dot anything -- there's no technical reason URLs need file extensions and they're just noise for users

Sunday, November 29, 2009

Implementing a State Machine on Rap Genius (Bonus: And Why!)

On Rap Genius we have songs that are "published" and those that are "works in progress". Recently we decided to streamline our editorial process by creating a third category ("under review") for songs that are basically complete and just need to be edited. Here's how I did it

Before the change

How were we distinguishing between published and non-published songs before adding the concept of "under review"? One strategy here is to add a field in your songs database table for is_published. This field would store a 1 if the song was published, and a 0 if it was unpublished.

This isn't bad, but it's more efficient to use a field called published_at, which stores either the time of publication if the song is published, or NULL if the song is unpublished. This strategy allows you to store the time of publication without using an extra field, and is what I was doing.

A false start

We could use the same approach for adding the concept of "under_review". I.e., we could add a field for nominated_for_publishing_at (I prefer "nominate for publishing" to "marked under review") that would store the time something was marked under review, and NULL if the song was not under review.

There are a few problems with this approach:

  1. It requires us to create a lot of fields.
    1. Both now. Actually I lied -- in addition to published_at, we also had published_by_id (which stored the user ID of the user who published the song). If we used this approach for adding "under review", we would also need nominated_for_review_by_id
    2. And later. Adding nominated_for_review_by_id isn't such a big deal, but suppose down the line we want to be able to mark some songs hidden (e.g., those with very few explanations). If we went with this approach, we would have to then add 2 more fields (hidden_at and hidden_by_id) -- obviously this strategy doesn't scale

  2. It doesn't capture the relationship between published and under review. Obviously a song cannot be both published and under review. This wasn't a problem before because the published_at field could only take one of two values, and so we didn't have to worry about any song ending up in an invalid state. Not so any longer -- we have to write our own application-level code to make sure that no song is both published and under review.

    It gets worse: once we've written the code that ensures that no song can be in more than one "state" simultaneously, we'll might need still more code to ensure that a song's state transitions are "valid". E.g., we might want to prohibit songs from transferring from published to under review, or maybe we want to require that songs pass through under review before getting published.
The right approach

The right approach here is to implement a state machine. Instead of dealing with several disconnected X_at fields, a state machine allows you to deal in concepts like:
  • State. A song can be in one state at a time
  • Events. A song has events (e.g., "publish") that transition from certain states to other states (e.g., under review to published). If you try to transition a song to an invalid state (e.g., straight to published without passing through under review), you get an error.
A state machine also solves the "lots of fields" problem. You only need 3 additional fields, no matter how many states you have:
  1. state
  2. state_updated_at
  3. state_updated_by_id
The best part is that building a state machine is a solved problem -- you don't have to write any of this code yourself.

My implementation

AASM (which kind of stands for "acts as state machine" -- for awhile it was voguish to name your Rails plugin "acts as whatever") is the most popular Rails state machine plugin (state_machine is actually better, but I couldn't get it to work). Here's my AASM state machine:



What's going on here?
  • 52: I tell AASM the name of the state column for my songs table (I believe the default here is aasm_state, which isn't ideal because it ties the state concept of your song model to your current state machine implementation -- I'd like to be able to swap out AASM for a different plugin without modifying my database schema)

  • 53: All songs start with state = "work_in_progress"

  • 55-57: Songs can also be "under_review", and "published". Note the information duplication here -- AASM should be able to infer that my default state ("work_in_progress") is valid without me having to list it again here. The same is true of the states listen in the transitions below; AASM should automatically recognize any state referenced by a transition as valid

  • 59-70: Song state transitions. Every transition is automatically exposed as a method I can call on any song object to change its state. For example, when I want to publish some_song, I'll call some_song.publish. Transitions also allow you to specify:
    • Valid to and from states. For example, it doesn't make sense to "nominate_for_publishing" an already-published song. By listing "work_in_progress" as the only valid from state for "nominate_for_publishing", I tell AASM to raise an error if I try to nominate a song for publishing that's in any state other than "work_in_progress"
    • Requirements for the state transition to take place. For example, the "publish" event will fail for any song that doesn't have a description, embed link, rating, and category
      • The implementation of guards is another design error in the AASM plugin. Specifically, the conditions for moving a song into a given state are likely to be identical to the conditions for being able to save a song that's already in that state. E.g., if I can't publish a song that lacks a description, I probably can't take an already-published song and remove its description. Since AASM doesn't take this into account, I have to duplicate the guard logic as a validation to account for the latter case:



    • A callback function to run on successful transition. I haven't implemented any yet, but it's easy to imagine an announce_new_song_to_mailing_list method that executes whenever a song is published
One last thing: how do I record who last-changed a song's state and when it happened? Ideally I could specify a callback function execute whenever any state transition took place, but AASM doesn't have the capability. So rather than add a callback to every single transition (and remember to add one to all future transitions), I implemented this functionality as a before_save callback on the song model itself:

Wednesday, October 28, 2009

Increasing information density on the Rap Genius front page

Idea

  • Designate 3 songs (randomly from our top n) as recommended with a star
  • Show published date for the 3 most recently published songs (makes it clear to new users that we're adding new content all the time)
Thoughts
  • Does it look weird for a song to be both "new" and "recommended"? (Like "Lord You Know" in the mock)
  • This idea makes me question the value of the other sortings -- i.e., do you really want to know the 7th-newest song? The 8th-best song?
  • This will get tricky once we can't fit all our songs on a single page

Friday, October 16, 2009

How to Load Disqus Comments Asynchronously (Bonus: And Why!)

What is Disqus?

Disqus is a drop-in commenting system that I'm using on Rap Genius. It solves these problems:
  1. Before Disqus, if you wanted comments on your non-blog website, you had to build the technology yourself (i.e., reinvent the wheel)
  2. Before Disqus, your comments were split across several identities -- you might comment with your Google account on Blogger blogs, maybe you have a Wordpress account you use on Wordpress blogs, and when you come across a blog that's neither Wordpress nor Blogger, maybe you leave an anonymous comment.

    With Disqus, you have one account (your Disqus account) that you can use at any site, which ties together all your comments and lowers the barrier to entry for commenting on new sites.
Disqus also has a few downsides:
  1. You have less flexibility with respect to user interactions on your site:
    1. You have to use a one-size fits all commenting form
    2. You have to use Disqus' copy -- e.g., "Add a comment", "2 comments and 3 reactions" (what's a reaction?). You can hack around this with clever Javascript, but it's still annoying
  2. You have to showcase the Disqus brand somewhat (and in turn dilute your own brand)
  3. Disqus' officially supported method for bringing its commenting form onto your site is very slow. Alleviating this slowness is the subject of this post.

The Problem

The web wasn't designed with "mashups" in mind, and thus importing content or functionality from another site into your page is always going to be somewhat hacky. At a high level, here's how Disqus works:
  1. Disqus gives you the URL of a remote Javascript file to include on your page
  2. Said Javascript rewrites part of your page to create the Disqus commenting form -- by default it hooks into the
    with the id "disqus_thread"
    1. An inherent problem of the way the web is designed is that this Javascript can do anything it wants -- for example it could steal your users' cookie (the equivalent of stealing the password of the current site).

      To use Disqus you have to be super-confident both that they're not malicious and that they'll take the necessary precautions to prevent someone who is malicious from getting control of the Javascript they serve.
  3. To submit a comment, the commenting form POSTs to the Disqus server using an iframe in order to overcome the same origin policy. (Don't sweat this part too much -- it's not related to the post and I don't totally understand it myself)
The Javascript Disqus gives you to include looks something like this:

<script type="text/javascript" src="http://disqus.com/forums/rapexegesis/embed.js"></script>

Unfortunately, including this Javascript file directly on your page (as Disqus suggests) is bad for performance. This is because browsers download and execute included Javascript files synchronously, meaning that everything else has to wait while the file downloads and runs.

Because of this, it would be disastrous to include this Javascript file at the top of your page -- doing so would mean that everything on the page (text, images, etc) would have to wait for the commenting form to load, which is bad because users can enjoy the page before the commenting form appears, and since it's at the bottom, users aren't likely to notice if it takes an extra 2-3 seconds to load.

Loading the comment form synchronously is a problem even if you include the Javascript at the bottom of your page because it will still delay any other Javascript that needs to run. For example, on Rap Genius, the Javascript that turns on the explanation tooltips couldn't run until the Disqus comment form loaded -- clearly not ideal

The Solution

A False Start

Ideally the Disqus comment form would load and execute asynchronously -- i.e., without making everything after it wait.

jQuery abstracts away the details of loading remote scripts asynchronously with its $.getScript() method, so ideally we should be able to just replace the inline script tag with this jQuery code (in our $(document).ready() callback):

$.getScript("http://disqus.com/forums/rapexegesis/embed.js");

Unfortunately, this produces a blank white screen. What gives?

What's Causing the Blank Screen?

Let's have a look at the source of the script we're loading (http://disqus.com/forums/rapexegesis/embed.js). This section in particular is interesting:

The Disqus Javascript is using document.write() to print the CSS necessary to style the Disqus comment box onto the page.

This is bad because document.write() can only be called before the DOM has loaded -- after the DOM has loaded document.write() makes no sense because there's no way to determine where the writing should take place. Because of this, the browser freaks out, and just overwrites the entire document -- in this case with a single style tag. This is what causes the blank screen.

Since the whole idea of our plan was to not block the loading of the DOM in order to load the Disqus comment form, Disqus' use of document.write() is a problem.

Why does Disqus use document.write() in the first place? Backwards compatibility -- precisely because it's so primitive, document.write() enjoys wide cross-browser support.

The Real Solution

Thankfully, Disqus leaves us an out -- if we set the window.disqus_no_style variable to false, the Disqus script won't use document.write() to load the styles, and our page won't get overwritten:

window.disqus_no_style = true;
$.getScript("http://disqus.com/forums/rapexegesis/embed.js")

However, we need some way of loading these styles in order that the Disqus form not look terrible. I copied them into a separate stylesheet and included it.

Thursday, August 27, 2009

What could possibly go wrong?

Taken at my office:

Saturday, August 22, 2009

Introducing BetterMetroNorth.com

Inspired by 37Better and Dustin Curtis' Dear American Airlines, I decided to re-design an interface that bothered me: the Metro-North train schedule finder. My re-design is less ambitious than its inspirations, but it has one crucial advantage: you can actually use it!

So check it out and leave me some feedback. Read on if you're interested in what I was thinking when I made the site.

What was I thinking?

Here's the form the MTA gives you to find a train schedule:


There are two main problems with this interface:
  1. Dropdown lists for picking stations. Selecting an item from a dropdown list is a pain in the ass -- it's much harder to click and scroll for the station you want than it is to just type the station's name. This is compounded by the fact that the first few letters are often enough to uniquely identify the station you're looking for.

    BMTA makes this easier by using autocompleting textboxes:


    This interface isn't perfect though -- what if you don't know the name of the station you're looking for? The ideal UI would be a combination of a dropdown and an autocomplete (a combo box). The user should be able to either choose from a list or start typing to make his selection (unfortunately implementing a combo box in the browser is tricky).

  2. Selecting departure time is painful. A calendar is a good interface for scheduling something. It helps you see where a new appointment would fit relative to others you've already planned. A calendar is not a good interface for communicating a fixed date you know in advance.

    Why? Well, if you know the exact date (say 9/1/2009) you don't need a calendar; you can just type it in. A calendar only comes into play when, instead of knowing the exact date of your trip, you have a description of how that date relates to today. So, for example, you might know that you're traveling this saturday, or two weeks from monday, and armed with a calendar you can translate this description into a fixed date.

    But why should you have to do this translation yourself? I.e., why not just tell the application that you want to see a schedule for "this saturday", or "two weeks from monday"?

    This is what BMTA tries to do. You can describe the day you want to leave in English (e.g., "wednesday") and BMTA will try to figure out what date you meant. Since parsing English is hard, I also provided a (more modern) calendar widget just in case.


After you pick a starting & destination station and a date, the MTA's site shows you the train schedule in a table that looks like this:


I have two small nitpicks and one big issue with this table.

Nitpicks:
  1. It shows travel time in minutes. Everyone is going to convert "80" into "1 hour 20 mins" in his head anyway, so why not display this format in the first place?

  2. It prints "THROUGH TRAIN" every time there's no transfer. This isn't necessary; show transfers if there are any, otherwise leave this blank.
Big issue:

The big issue with this table table is its treatment of fares.

It shows you whether each train requires purchasing a peak fare ticket, but it doesn't show you the fare itself. If want to see the fare, you have to click away from the schedule to this rather painful table:


Is this from the MTA's site or the movie Brazil?

The problem with this table is that, by making all rows and columns look the same, it assumes you're equally likely to look up each kind of fare. The table should be optimized so that prices of frequently-purchased tickets (e.g., a one way peak ticket purchased in the station) are easier to find than those of infrequently-purchased tickets (e.g,. a ten trip senior ticket purchased via webticket).

BMTA, on the other hand, shows you the fare information you're mostly likely to need along with your train schedule: whether a given fare is peak (because you need to specify this when you buy your ticket) and the price of a one-way ticket:

Conclusion

It has some other niceties, but these are the main ideas behind BetterMetroNorth.com.

Is BMTA the perfect way to look up and display train schedules? Of course not.

I'm sure there are others, but here's one problem with BMTA: It's not immediately clear from the table of train departures how soon a given train leaves after the one before it.

I.e., trains that leave 2 hours apart appear as consecutive rows just like trains that leave 15 minutes apart. Ideally the table rows would be spaced according to how close the corresponding departure times are. Trains that leave 15 minutes apart would be represented as consecutive rows, whereas trains that leave 2 hours apart would have several blank rows between them. This would make it much easier to determine at a glance how costly it is to miss a given train.

So yeah, let me know if you can think of any other improvements. Alternatively, feel free to create your own schedule site and write a blog post bashing mine (at the time of writing BetterBetterMetroNorth.com is available, so go nuts).

Thursday, July 16, 2009

Amazon Authentication Annoyances

Amazon's interface for signing in and out is pretty confusing.

Signing In

The only way to sign in is to click "personalized recommendations". The "sign in" text isn't clickable.

Signing Out

The only way to sign out is to click the name of the person who's signed in:

Clicking someone's name generally takes some action specific to that person (e.g., opening an email to him). At the very least, Amazon should have made the entire sentence ("Not Tom Lehman?") a link. (HT Ilan).

Thursday, June 11, 2009

Photoshop "Save" Dialog Considered Harmful



This is the "Save" dialog in Adobe Photoshop. Notice that the incredibly common and useful PNG file format appears semi-anonymously among a bunch of obscure, out of date file formats that no one ever needs. How obscure? From the wikipedia page for PCX:
PCX is an image file format developed by the ZSoft Corporation of Marietta, Georgia, USA. It was the native file format for PC Paintbrush (PCX = "Personal Computer Exchange") and became one of the first widely accepted DOS imaging standards, although its use has since been succeeded by more sophisticated image formats such as GIF, JPEG, and PNG.
Options the user is more likely to select should be more prominent. This is for two reasons:
  1. It helps advanced users pick the option they're likely to want more quickly.
  2. It guides beginning users to the option that's probably right for them. A beginner might spend time deciding between PNG and PCX in the existing menu because it does nothing to suggest that PNG is far more likely to be the right choice.
Here's a redesigned interface that obeys this principle:


This interface isn't perfect though. One problem is that the parenthetical text is much more useful than the actual file format names. Another more subtle problem is that this interface implies that all 3 main options are equally important. In reality though, there are only two choices:
  1. I want to save this image and resume work later. When I open the file, the image should look exactly as it does now, including layers, history, etc. (In this case, the user wants a PSD)
  2. I want to save this image and share it with someone else. I won't be able to pick up where I left off in Photoshop, but my friends will be able to view the image without having Photoshop installed. (The user wants PNG or JPG).
The interface should allow the user to use this mental model and make the correct technical decision internally:


This interface is better, but it still raises the question: Why should I have to choose between the ability to resume work later and the ability to share? Obviously you shouldn't, but this is a deeper problem -- one that Photoshop can't really solve, and perhaps the topic for a future post.

Monday, May 4, 2009

Faucets & Orthogonality

Things that aren't conceptually related should not be linked in interfaces. This principle of interface design is called orthogonality (if I may slip into italics for a moment). The classic example of a non-orthogonal interface is that of the helicopter:

A helicopter has four main controls: foot pedals, collective pitch lever, cyclic, and throttle. The foot pedals control the tail rotor. With the foot pedals you can counteract the torque of the main blade and, basically, point the nose where you want the helicopter to go. The collective pitch lever, which you hold in your left hand, controls the pitch on the rotor blades. This lets you control the amount of lift the blades generate. The cyclic, which you hold in your right hand, can tip one section of the blade. Move the cyclic, and the helicopter moves in the corresponding direction. The throttle sits at the end of the pitch lever.

It sounds fairly simple. You can use the pedals to point the helicopter where you want it to go. You can use the collective to move up and down. Unfortunately, though, because of the aerodynamics and gyroscopic effects of the blades, all these controls are related. So one small change, such as lowering the collective, causes the helicopter to dip and turn to one side. You have to counteract every change you make with corresponding opposing forces on the other controls. However, by doing that, you introduce more changes to the original control. So you're constantly dancing on all the controls to keep the helicopter stable.
A better, less confusing example of a non-orthogonal system is the late 20th century faucet:


Figure 1

The left knob controls the flow of hot water and the right knob to control the flow of cold water. This interface is not orthogonal because it links the two conceptually unrelated concepts of water temperature and water flow rate -- it's impossible to change one without affecting the other. (This interface is plagued by more than orthogonality issues -- to wit, it gives no indication which knob controls hot/cold or which direction one should turn a knob to increase flow).

How can we fix this interface? First of all, we can make it orthogonal:


Figure 2

Now lifting the handle increases the flow, and rotating it changes the temperature -- it's possible to adjust one without changing the other. This implementation also makes it clear which direction is hot and which is cold. Finally, it makes it possible to control every aspect of the system with one hand.

Is there still room for improvement? Consider these observations:
  1. Users don't need granular control over flow rate, they just want it to be always set at something reasonable when the faucet is on (probably the maximum allowable rate).
  2. Users don't need that much control over temperature. The faucets in both figures allow the user to choose between hundreds of temperature settings, far more than people need.
A better solution would be one that gives the user only one choice of flow rate (off v. on) and 4 or 5 choices of temperature. Unfortunately temperature preferences vary, and thus it would be difficult to settle on which 4 or 5 temperatures to provide (without calibration, which is costly). Furthermore, it's pretty easy to control the flow via the interface in figure 2 as if it only had two settings (i.e., handle fully up or handle fully down).

Ignoring the temperature problem for now, we could simplify the interface by removing the user's ability to pick flow rate via a faucet functionally equivalent to this one:


Figure 3

Opening it even a little increases flow to the maximum level and sets the temperature to cold. Further opening it increases the temperature (while keeping the flow level constant). This is simpler than the interface in Figure 2 because the user only has to operate it on a single dimension (turn left / turn right v. lift / depress & rotate left / rotate right). Despite its simplicity, this interface has two disadvantages relative to the one in Figure 2:
  • It's not clear which direction one should rotate to make the water hotter v. colder
  • You have to make the water maximally cold before you can turn it off (though you can mitigate this by turning it off quickly).
So yeah, who among us is able to unbate his breath while awaiting the faucet innovations coming in the next century?

Thursday, April 30, 2009

Blogs are great, but they suck part 2: In which I remake the face of the earth

Big news: I'm creating a new blogging platform based on the principles I outlined in Blogs are great, but the suck (part 1).

While that post covered some specific problems with blog archives, my new platform has a broader goal. The use case I'm concerned with is this:

You just stumbled upon a blog you like (either via stumbleupon.com or a legacy stumbling platform). Now what?

Well, one thing you can do is make sure you'll read future updates by subscribing to its RSS feed. Google Reader solves this problem quite nicely.

However, unless the blog's posts have a short shelf-life (e.g., politics, celebrity gossip, etc -- you probably shouldn't be reading this shit anyway. If something isn't going to be interesting to you in 6 months, it probably isn't that interesting now; you're just bored. This is why I don't read the economist, but I digress!) you probably want to read some of the blog's already-published content as well. Unfortunately, this is impossible.

One "solution" is to peruse the blog's archives. I sounded off at length in part 1 about how frustrating this is, so I'll only summarize the issue here:

A blog archive is merely a labor-intensive mechanism for picking a random blog post to read.

Here's the workflow: pick a year at random (with the slight anxietythat you're doing something wrong), pick a month at random (same anxiety), read a post at random. Repeat.

There's nothing wrong with reading posts at random, but why should it be so difficult?

Take a look at http://randomdelino.heroku.com -- this simple site shows you a random delino post every time you click a button, and despite ostensibly having less functionality, it's strictly better than the delino archives.

So fine, users of my new blogging platform will have the ability to see a random post. What else will it do?



The spec

Here are the basic ideas:

  • Break up blog posts into useful chunks.
  • Provide good sorting for those chunks.
  • No pagination (or, more broadly, don't make the user request content).

Chunks

Each blog will have the following sections:
  • A section displaying all posts (default).
  • A "best of" section. Originally I called this "starred posts", but I've decided that Web 2.0's obsession with "starring" is insane.
  • A section containing only longer posts
  • A section containing only shorter posts ("quick hits")

Sorting

Every section above can be sorted in the following ways:
  • Newest first
  • Oldest first
  • Shuffle (i.e., randomize every time you click)
  • Posts with more comments first.

No Pagination

As I wrote in Part 1, when I'm done reading your blog, I'll leave. If I'm still around after reaching the bottom of a page, obviously I want more content -- don't make me click "Older Posts" to get it! There are two strategies for killing pagination:
  1. Expandable Snippets. Put all the posts on a single page. Show full blog posts for the first 10 (or so), the first 200 words of the next 40 (or so), and just titles for the rest. Clicking any incomplete post expands it inline (quickly, I hope). This is roughly an enhanced version of Google Reader's "List View"
  2. Endless Page. Show the first 10 posts in their entirety. When the user scrolls to the bottom, pull in the next 10 in their entirety automatically. This is roughly Google Reader's "Expanded View".
Which is better? The endless page model requires fewer clicks (though the user is likely scrolling with the mousewheel, and thus his hand is probably on the mouse already), but it's more jarring, doesn't give the user an indication of how many total posts there are, and frustrates in-page browser search.

Open Questions

  • What's the best way to avoid pagination?
  • How should the platform deal with posts meant to be read in series / together?
  • Should readers be able to rate posts?
  • Tags / Labels? Are these useful for anything besides jokes?
  • What should I call this thing?

Sunday, March 15, 2009

Sane URLs

What is up with your URLs, eBay? When you click a link from an eBay search, you go to a URL that looks like this:

http://cgi.ebay.com/Bernard-Madoff-Ceramic-Coffee-Mug-Hard-to-get_W0QQitemZ200319297841QQcmdZViewItemQQptZLH_DefaultDomain_0?hash=item200319297841&_trksid=p3286.c0.m14&_trkparms=72%3A1205|66%3A2|65%3A12|39%3A1|240%3A1318|301%3A0|293%3A1|294%3A50

This is obviously insane -- there's no reason URLs can't be both unambiguous and human-readable.

Some guidelines:
  • The domain should make sense. What the fuck is "cgi"? This is gibberish to any non-technical user. The domain should just be "www.ebay.com" (I'm looking in your direction, www2.seamlessweb.com).
  • Since URLs need to unambiguously point to a single page, it won't generally be possible to make them entirely human-readable. However, you should limit the non-human-readable portion of the URL to the shortest string necessary to ensure uniqueness.
  • URLs should include additional text to make them easy to identify. eBay actually does an okay job of this by including "Bernard-Madoff-Ceramic-Coffee-Mug-Hard-to-get", but ideally this should appear at the end of the URL.
Here's a quick improvement on that eBay URL:

http://ebay.com/auctions/123456/Bernard-Madoff-Ceramic-Coffee-Mug-Hard-to-get

where "123456" is the auction's unique internal id. Of course http://ebay.com/auctions/123456/ should work as well (since the auction is uniquely identified by the numeric string).

This is a good generic solution, but we might be able to do even better. I.e., there might be a more human-readable way to make the URL unique than embedding the auction's internal id. For example, eBay could use a Blogger-like strategy:

http://ebay.com/auctions/end-date-20090315/Bernard-Madoff-Ceramic-Coffee-Mug-Hard-to-get.

If two auctions with the same name share an end date, append a number to the end of the URL. If you want to avoid this, you could add information about the seller to the URL:

http://ebay.com/auctions/seller-rogrpodcater/end-date-20090315/Bernard-Madoff-Ceramic-Coffee-Mug-Hard-to-get.

The nice part about this solution is that you could have http://ebay.com/auctions/seller-rogrpodcater take you to a page listing all of rogrpodacter's auctions. The downside to this solution is that now the URL is getting pretty long.

There will always be a tension in URLs between human-readability, unambiguousness, and brevity. The important thing is making sure that you don't sacrifice one value without improving another.

Thursday, March 12, 2009

Blogger templates and WYSIWYG editors

Here's how you select a template for your blogger blog:



Nice and rounded corner-y, right?

But what if I want to customize my template a little; for example by increasing the size of my blog's title or changing the color of the date headlines?

Ugh. I have to look through the raw HTML to find the right CSS class or id:
Click "Edit HTML" in the Blogger Layout tab, find the right CSS selector, and then enter the color I want in hexadecimal format:
Making this minor change requires the same level of expertise as creating an entirely new template.

So what's a better interface?

One thought is to go as high-level as possible: let users adjust page elements' properties by right clicking on them. To change the color of the date headlines, just right click on one, select "Change color", and you're done.

This interface is friendlier, but its ease of use comes at a cost (or, put another way, there are benefits to working with the raw HTML/CSS, frustrating though it can be). Consider: when you select "Change color" on a date heading, how can Blogger determine whether you want to change the color:
  1. Of every date heading on your blog
  2. Of the first date heading on every page
  3. Of just this particular date heading (perhaps it's your birthday)
If you give the user enough control to specify which one of these he means, you end up with an interface just as complicated as HTML/CSS.

So while my proposed WYSIWYG interface for configuring Blogger templates could supplement the existing interface (say by only allowing you to use it for blog-wide changes), it's not powerful enough to replace it.

This shortcoming is actually an instance of a more general class of problems that plague all WYSIWYG editors -- i.e., an interface that only lets you modify the way an individual element in a document looks cannot always capture your intent (since changing the formatting of an individual element can be in aid of any number of higher-level goals).

This is why using Word is such a pain in the ass. There's no easy way to specify whether you're bolding a line because it's a chapter heading (and therefore you want all other chapter headings to be bolded automatically), or just because you're trying to emphasize it. Word's default behavior is to assume that every change is local, which is fine until you have to change the font of 50 chapter titles manually.

Friday, October 17, 2008

Thoughts on the Firefox 3.1 new tab page

Aza has a nice post describing the latest spec for the new tab page in Firefox 3.1. For some additional background, read the concept post.

The basic idea is to put some useful content into the (currently blank) screen that appears when you open a new tab. Since users frequently open new tabs to do something with text they just copied (search, map an address, define a word), why not add actions to the new tab page based on what the user selected in the previous tab. Here's Aza's example:

This is pretty good, but you still have to actually click to get the data you want. As Aza puts it, "Don’t force the user to ask for more content: just give it to them". In other words, don't make the user click "Map 3312 Main Street, Pacifica"; just put the map right in the new tab page:

A map this small might not always be useful (though in real life you could probably make it a bit bigger), but the user can always click it to view the whole thing. Maps are also a particularly tough case -- you're almost always going to be able to fit a complete definition or translation on the new tab page.

Now, one potential downside to this proposal is speed. The new tab page has to load instantaneously, and you pay a performance penalty if you have to look up a map every time you load it. If the user isn't interested in a map (i.e., he just happened to have mappable text selected), he's not going to be willing to wait.

However, there's no reason this extra content must load synchronously. The new tab page could load its basic content first (the links in Aza's mockup), and then get the richer content in the background once the user can already interact with it. This means you'd have to put a little throbber in each button while the content was loading:

And the user might have to wait a second or two to see it, but this is still much better than having to click. Furthermore, if the user isn't interested in the additional content, its loading won't disrupt his experience.

Wednesday, September 10, 2008

Rich Berger's America

Rich Berger's America is a land in which women would be forced into back-alley abortions, blacks would sit at segregated lunch counters, rogue police could break down citizens' doors in midnight raids, schoolchildren could not be taught about evolution, writers and artists could be censored at the whim of the Government...

Here is how you choose what you want on your sandwich in Rich Berger's America (i.e., when you use Seamlessweb, whose interface Rich just helped re-design):


Notice the instructions to "Scroll down for more options". This is pretty annoying. You can't see everything you've selected at once, and when there are a lot of options (e.g., you're ordering a custom sandwich) you end up scrolling up and down a few times to double check your entry.

Oh well, Rich wouldn't do this unless it were absolutely necessary, right? Wrong. Take a look at the order customization dialog box in context:


When you click on a menu item to add it to your order, the entire browser window goes grey and this tiny dialog box pops up to allow you to customize your choice.

This is obviously insane. Seamlessweb is forcing its users to scroll in order to make room for more empty grey filler. These AJAX-y modal dialogs look cool, but they make Seamlessweb harder to use. Prior to the redesign, clicking an item took you to a separate page to customize it. This was slower, but at least you didn't have to scroll all over the place.

I would suggest either:
  1. Expanding the dialog box as much as possible and loading a new page for the items that would still require substantial scrolling.
  2. Putting the customization options inline in the menu itself.

Saturday, September 6, 2008

Blogs are great, but they suck

Reading blog archives is an incredible chore:

  1. Select an arbitrary month in the past
  2. Read the posts from that month
  3. When finished, select another month
  4. Repeat
There are 2* problems with this approach:
  1. It makes me ask for more content. When I'm done reading your blog, I'll leave. If I'm still around after getting to the bottom of a page, obviously I want more content -- don't make me click somewhere to get it!
  2. Content is split into arbitrary chunks along a dimension that I don't care about: time. I have to choose between reading posts from May 2006 and June 2006, but I don't care -- I just want to get to the most interesting content, whatever month it's in.
2 deserves a bit more discussion. Every blog and RSS Reader presents data sorted along the same lousy dimension: time. This doesn't make sense. The top post on a blog should be the most interesting one, and only rarely (e.g., in the case of blogs that track bargains) will the most interesting post be the most recent.

It's even worse for blog archives: obviously if I'm going through your archives I don't care about the order of the posts. What difference could a month possibly make 2 years later?

So how should blogs and RSS readers work? First of all, the user should be able to access every post on the blog without clicking anything. Rather than breaking up the blog into chunks by date, every post should be on a single page sorted by relevance.

How do we fit a whole blog onto a single page? We start by taking real estate away from less relevant posts. Only the top-most (/ most relevant) posts should have their full content on the blog's main page. As you scroll down though, you should get smaller and smaller excerpts from posts until you only see post titles. Clicking on any part of an excerpt should fill in the full content (inline preferably).

If the page is still too big, you could split the list up into several pages, and automatically advance pages when the user reaches the bottom of one.

So what sort order do you use? Well, first you need a metric for gauging quality. I don't have all the answers, but it doesn't take much to improve on the status quo. Potential things you could take into account: comments, links from other websites, diggs, numbers of times it's shared via other websites (facebook, etc), traffic relative to other posts.

If you have the ability to mark a post read (as you do in an RSS reader), then we're done. Just order the posts by quality, removing posts they get read.

If you don't have the ability to mark a post as read (as is the case with blog websites), things are a little trickier. In this case you have to put at least some of the recent posts at the top, otherwise you're going to annoy your frequent visitors.

Scroll down a bit though, and quality should begin to have an effect on a post's ranking in the list. Scroll down more and quality becomes the only factor. At the top of the blog you have a link for new users to click that will quickly scroll past the new posts.

* Is there any justification for spelling out the names of small numbers rather than using numerals? Numerals take up less space and are easier to read.

Friday, August 8, 2008

iPhone interface / usability comments

First, take a look at Edward Tufte's bomb video:

video

Here are some of my own complaints:
  1. You have to set your "Favorite" contacts manually (the phone should pick automatically from your most recently called / emailed contacts)
  2. Update: This is false -- my bad. You can't change the order of your "Favorite" contacts (each contact is ordered based on when it was added to favorites -- this is pretty insane)
  3. When you look at your contacts within the interface for making a call, contacts without phone numbers should be filtered out
  4. The interface for accepting / canceling an auto-correct suggestion is impossibly small:Furthermore, the dictionary the iPhone uses to auto-correct is a tad formal (e.g., it doesn't include "yo"). (To apple's credit though, the dictionary does include the names of your contacts)
  5. Many interfaces have only a single text input area (e.g., Google Maps, Contacts, Safari (unless the page has a form)). There should be an hardware button that brings focus to this input area (or the "first" input area in the case that there are multiple) and activates the keyboard. This would:
    • Save space since the text entry field would no longer have to always be present (it's always present now since you need to tap it to begin entering text)
    • Make it easier to begin editing (sometimes the input form is a difficult target)
  6. The weather icon on the main screen doesn't update with the current weather (it always says 73 degrees). (This sort of thing is definitely possible; e.g., the calendar icon always updates to show the current date)
  7. No copy-paste functionality (I'm not the first to point this out, but it's pretty egregious)
  8. If you want to compose a text message while out of service and send it as soon as service resumes, you have to do it manually (there's no "SMS Outbox")

Saturday, July 5, 2008

Tabs are actually OK though


This is a screenshot of the Cisco IP Communicator software. You can use it to make phone calls on your computer over the internet, which is cool because it uses your office extension so you can work from anywhere without having to tell your work friends to call a different number.

It is also a great example of software whose UI uses a metaphor -- a term I'll apply to interfaces that are designed to evoke a familiar non-software object to encourage ease of use. CIPC looks and behaves exactly like the physical phone sitting on your desk, so you know how to use it without having to learn anything new.

This makes interfaces that use recognizable metaphors attractive, but metaphors often do more harm than good:

  1. Most metaphors are incomplete -- software generally doesn't exactly mirror the object its interface is based on -- and it's hard for users to understand how software will function when the metaphor fails. For example, even after you empty the "trash can" in OS X, your files are still recoverable, even though the trash can metaphor suggests they are gone forever (or at least inaccessible).
  2. (And More Importantly) Metaphors are often based on objects that would have been designed differently if the capabilities of a computer were available to them. CIPC is a great example of this. The designers of the OG phone would have loved to have a full keyboard, high resolution screen, and copious processing power available to them when they were designing the phone. Why should computer software mimic items that were designed the way they were because they couldn't take advantage of a computer? In the CIPC case, for example, all you have to do is give me an autocompleting text box to type the name of the person I want to call.

The trash can I mentioned in (1) is also relevant for (2). Why should I have to "move" something to delete it? Pressing "delete" should cause the file to disappear, viewable (in its original directory) if I do something like View » Show Deleted Items.

For that matter, why should there be any concept of "emptying the trash" i.e., (per the metaphor) "deleting files forever"? When you "empty the trash", what's actually going on is the operating system designates those files "safe to write over with other data". However, the operating system should be smart enough not to write over any of these "deleted" files until it has to. In the case of a 50Kb Word document on a 1000GB hard drive, this should be virtually never. There's no good trash can-like metaphor for a filesystem that saves every version of every document, and maybe this makes such a system harder for a beginner to understand; but the benefits it would offer to intermediate and advanced users would more than compensate.

Another good example of this is the filing cabinet / folder metaphor for organizing files. (As a side point, this metaphor isn't even that strong -- no physical filing cabinet has folders nested 10 levels deep, and the fact that you can do this on a computer is confusing to beginning users). In a physical filing cabinet, a document can only be in one folder. However, on a computer, a single "file" can be "placed" in any number of "folders". Why can't I describe "Annual Report.doc" as both Categories » Work » Reports » Annual Report.doc and Time » 2008 » December » Annual Report.doc? (Google Docs is moving in this direction -- it's about time).

Saturday, June 28, 2008

Form over Function

Oh great -- a Brazil-esque bureaucratic nightmare.

Forms can be usability disasters:

Forms force you to use the mouse.

Many forms use radio buttons or dropdown menus under the theory that users are more comfortable "picking from lists" rather than just entering data off the top of their heads. Most of the time though, especially when users are confident in their answers, it's just easier to let them type the answers directly rather than requiring users to shift hand positions several times while entering a small amount of data.

Dropdown menus are particularly useless. They are useful when users have to pick from a list of values, but it's almost always easier to pick values from an autocompleting list than scan (and possibly scroll) down a dropdown:


Dropdowns are easier to navigate when there are fewer options, but in this case radio buttons are often even better. If you must have a dropdown, at least give users the ability enter values with the keyboard in addition to choosing from a list.

Forms often request unnecessary information

Why do I have to enter my city, state, and zipcode whenever I want something delivered? City and state are derivable from zipcode! Mint.com is one of the only websites that gets this right:


Also notice that Mint validates your entry automatically without your having to press submit. Once a form is submitted, the only way it can notify users about problems is to reload the page. But when the page gets reloaded like this, users don't know what state their data is in. Can they just correct the one error? Or do they have to re-enter other information that was previously entered correctly. Many websites clear password fields in this case, many do not.

Forms are often unnecessary

The reason to force users to fill out a form is to gather explicitly structured data -- you want to know that this part is the city, this other part is the zipcode, etc. However, it's not always necessary to force users to explicitly structure the data they enter; often it's possible to parse their plain text entry and guess at the structure. (This is particularly effective when it's easy for users to correct errors).

For example, imagine if Google Maps used a conventional form to ask you for an address:


Google Maps doesn't ask you to structure your input because it's possible to guess what you mean by looking at an unstructured string of text. There's no reason that online vendors couldn't use this same strategy.

Here is my ideal address entry "form":


You enter any string in the address box that unambiguously identifies your location. The map and postal address below update automatically so you can see if what you've entered is incorrect.

Sunday, June 15, 2008

Show Don't Tell

Here's a nice little interface from the Mac's Keyboard & Mouse preferences. The window on the right shows a video of someone performing the action that you're deciding whether to enable on the left. This allows for fewer words on the left since they don't have to write out something like "Allow tapping with two fingers simultaneously to count as a secondary click".

Of course the worst possible option is to keep a sparse description, but add no graphic content to fill in the gaps. Take this interface from FireFox, for example:What the fuck is "smooth scrolling"? The name explains nothing (unlike the excellent "Check my spelling as I type"), and we're given no context from it's location in options (Options » Advanced » General » Browsing). Finally, the name gives no indication of what would make me want to turn it on or off -- what's the alternative to "smooth" scrolling -- "jerky" scrolling? That sounds terrible!

There is no analogous option in the Safari browser since Safari just makes the decision for you. This offers less flexibility, but functionally FireFox is doing the same thing since no one will ever experience "smooth scrolling", decide that he doesn't like it, and know to look for this option.

Of course Safari has demons of its own (Ariel just heard me say that aloud to myself as he emerged from the shower). Take for example this dialog that it pops when you try to close multiple tabs:In an ideal world of course, this dialog wouldn't be necessary. If you tried to close Safari in this situation, it would just close, and if this were an accident you could easily restore your old tabs. We're getting there, but this dialog is probably still necessary.

However, compare this dialog to the exact same dialog in FireFox:Safari's version:

  1. Has an unnecessary amount of header text ("Are you sure you want to close this window?" versus "Confirm Close.")
  2. Makes the most important piece of information (the number of open tabs) too small (I would prefer it were bigger in the FireFox version as well)
  3. Doesn't allow the user to preempt future annoyances by unchecking "Warn me..." (this isn't a great UI pattern since the user might be afraid to un-check this box since there's no obvious way to re-check it, but it's probably better to have the box than to not).
I'd improve on both versions by emphasizing the relevant information (the number of tabs), and cutting down on filler text, particularly jargon (e.g., "window"). What about this:

Tuesday, May 13, 2008

Design Within Reach

These days you can pay for a taxi with a credit card by making selections on a small touch-screen mounted to the back of the front seat. Interestingly, the screen can have one of two different user interfaces, and one of them has a design flaw.

After the flawed system asks you to enter your tip, it brings you to a new screen that says something like "Your total is $10.40. Is this okay?" If you touch "Yes", you are taken to another screen that asks you to swipe your credit card.

But the screen that asks you to swipe your credit card has a "back" button that allows you to re-enter your tip! This back button makes the "Your total is $10.40. Is this okay?" screen superfluous -- i.e., if the software just assumed the answer was "yes", the the user would lose nothing (because he could always press "back" from the swipe screen). And indeed the other, non-flawed, user interface skips this confirmation screen (i.e., assumes the user pressed "yes").

There is a similar design flaw in Wii Tennis: when a match is over, you are asked whether you want to "Play Again" or "Quit". If you select "Play Again", you're asked whether you want to play 1, 3, or 5 games. Instead, the game should give you an interface that looks like this (where words in brackets represent choices / buttons):

[Quit]

Play Again: [1 game] [3 games] [5 games]

Many user interfaces are flawed in this respect. For example, we're all familiar with software that constantly asks "Are you sure?". Don't ask me if I'm sure! Just go ahead and do whatever it is, and give me the option to undo it if necessary. This way if I was sure I don't waste any time, and if I wasn't sure I lose nothing.

Gmail was basically the first web application to get this right:


As a prize for making it this far, here's a comic example of bad design from my office kitchen:


Oh, cool, two drawers next to each other with ambiguous names. One contains something that I need all the time (forks) and the other contains stuff that's never been used in my company's history (ice cream scoops and spaghetti servers). Nice work FACILITIES.