interface

Recognising a search box when you see one

If you suspect I secretly like clutter for its own sake, you should see the state of our living room. Then you'll know it for sure.

Every few days there's an interesting article proposing new interfaces at UXmovement. It's like a serialized release of a new Tufte book, not always what you agree with, but invariably both thought-provoking and affirming.

I've broadly agreed with almost everything I've seen there in the past few weeks, including having a few "wow, yeah!" moments. So it's only when I think there's room for discussion that I'm blogging about it, and I hope that it doesn't come across as caviling! A recent post talks about simplifying the "search hotspot" on your websites by moving elements around. I like the ideas behind this simplification, but it would definitely need testing, especially as a lot of influential sites (including Amazon) moved in the other direction years ago.

The major problem I foresee is not so much ambiguity: the ambiguity is eventually resolved by the text on the button. It's more to do with how you optimize an interface for "just-in-time" disambiguation. People in the Western world largely read from left to right (although you could swap "left" and "right" in this blogpost and it wouldn't matter so much), so forcing people to look first at an empty box on the left, wonder what it is, continue right, then see the button, then---"aha! that box I just saw a half-second ago was a search text box!"---look back to the box in order to search... this complicated just-after-time disambiguation slows the user down, and makes them cumulatively uncertain using your site.

"Search" in a right-hand button disambiguates retroactively, whereas you'd ideally want the user to be disabused of any notions before they even get to the box. Accessibility points directly at the issue here, serving as the canary in the coal-mine. The way that the proposed alternatives don't meet accessibility guidelines---no labels for the text box or the dropdown---suggests that the only thing that ever truly disambiguates an input element is, ultimately, a label. And this label typically sits (or is read out by a screen reader) before the box, not after it.

The suggestions on the most recent UXmovement post are also not consistent with guidelines in a previous post about why users fill out forms faster with top-aligned labels. What do I mean by that? Well, in that post, very close label/input combinations in a clear single visual direction are treated as a single step; back-and-forth combinations comprise multiple steps.

Just for fun, let's give two of UXmovement's suggestions their own treatment:

User "eye-tracking" workflows of two search grammars

Here we see the behaviour I discuss above. In the first example, the eye travels from the search label/input (which it fills in) to the go button: two steps. In the second, the eye sees the input box; looks right for clarification; looks back to the beginning of the input field to fill it in; moves back to the search button to click it: four steps.

Does that really mean there's a problem here? Does consistency between different parts of a web interface matter? Well, I have to stress that, as with accessibility, inconsistency is not a deal-breaker for a new interface; but you have to be sure that the widely accepted "visual grammar of search" and plain observed user behaviour supports the contextual changes you make to your UX guidelines. The user is key. You want to keep them as happy and as certain as possible: they have to continue to trust their weight to your interface.

Who knows? You might find in usability testing that people are so used to the visual grammar of search---a box in the top-right means "search"---that you could get away with no button at all, and people would figure it out with a low failure rate.

Inconsistency is fine. Inaccessibility---when we're prototyping new user interfaces, and accessibility with slow-moving web standards is often post hoc however hard we try---is OK, but it needs to get sorted before production releases. And clutter is completely excusable, if that clutter makes every next step a no-brainer.

If the user needs clutter, provide clutter; if they don't, don't. Your user interface does not have to be a show home. It just has to work.

Blog category:

Spliticket running again with BeautifulSoup

Or, how I learned to stop parsing and love the soup

Ages ago Matthew Somerville emailed me to say that spliticket had fallen over. It's my hacky interface to his wiki page documenting split tickets, and ultimately it found the vagaries of even wiki-generated HTML a bit too hard to cope with.

At the time I built the HTML parser using core SAX-based HTML parsing, and it was horrible. SAX works in a basic sense, but you have to build your own internal state engine, track which elements have gone past while working out what to do with the current context, and even write rules for what to do when the underlying dumb parser encounters HTML entities: no mean feat when the document is peppered with – en dashes.

Not only was writing the rules initially a pain in the rear, but adding new rules and bugfixing the existing ones was even worse. But I lived with SAX, because I was deploying on shared hosting: I presumed that this was the best option available if I couldn't install any new shared libraries.

Not true! I've just rebuilt the entire parsing layer with Beautiful Soup, a Python HTML/XML parser library which (a) is available as a single file and (b) works out a decent HTML DOM tree from pretty much anything you throw at it.

Try it yourself, if you have to do any HTML parsing.It's astonishing; beautiful, in fact. I will never write another SAX parser ever again, which I'm sure I've said before.

How to see Last.fm from the other side of the room with LastJS

Proof of concept, more than anything else: how to hook up to a recalcitrant Flash-based interface.

Back from a rather physical near-week of team building with work, I’ve been listening to Last.fm today to recuperate and nurse my tired muscles. But with the music playing on our crusty, trusty old purple iMac in one corner, and me in the other reading, drinking tea or otherwise recuperating, how can I tell at a glance what the current artist is?

Last.fm’s web interface isn’t optimized for the sort of “media station” use we put it to, and their downloadable widget won’t work on the antiquated version of OSX that I’ve just about managed to squeeze onto dear old Purpurea. So today I’ve spent some time writing a bookmarklet to allow me (and you, dear reader) to hook into Last.fm and its Flash player’s behaviour, to update a larger-view popup window with the necessary information.

Here’s the bookmarklet—which with attention to catchy names I’ve called LastJS—with spaces added for legibility:

javascript:void(function(){
  var s1=document.createElement(’script’);
  var s2=document.createElement(’script’);
  s1.src=’http://www.jpstacey.info/applications/lastjs/jquery.js’;
  s2.src=’http://www.jpstacey.info/applications/lastjs/last.js’;

  var h=document.getElementsByTagName(’head’)[0];
  h.appendChild(s1);
  h.appendChild(s2);
}())

(As the above suggests, the bulk of the code is at http://www.jpstacey.info/applications/lastjs/last.js.)

And here’s what you need to do to use it:

  1. Add this link to your browser favourites (IE7) or bookmarks (everyone else): LastJS bookmarklet.
  2. While on a Last.FM “now playing” page e.g. for The Hold Steady, click the bookmarklet.
  3. This will pull an instance of jQuery and LastJS off my own server, and add a “click for big” link under the title.
  4. Click on the link. A new window will open, containing the artist information (track information is a bit obfuscated until the Flash player loads the next track).
  5. Wait. As the track changes, the new window will update with the new track information.
  6. The text is purposefully large yet not too large. If you’ve got a big monitor you can make it even bigger by increasing the base font size in your browser. To do this in Firefox press CTRL-+ (or Apple-+); I think it’s something similar in IE7.

Feel free to poke around at the code, and distribute it (under GPL, for what it’s worth: I tried looking into precisely which variant I wanted but my knees started to ache). Here are some of the problems it has to solve:

  1. Last.fm uses Prototype, and so needs jQuery to restore the $ variable using jQuery.noConflict().
  2. Events in the Flash player trigger functions in the window scope: by putting a new method in for a given event handler you can hook into Flash events. Care has to be taken, though, not to wrap and re-wrap too often—the bookmarklet might after all be re-clicked—or you might provoke a recursion warning.
  3. Popup blockers mean that you can’t always guarantee the window will exist, and the code has to check accordingly.
  4. Firefox seems to blank the contents of the popup window shortly after it’s opened, so any writing of text to it has to be delayed, lest it be lost by this clear-out.

All probably needs work, but feel free to have a play. It doesn’t circumvent any DRM or anything, of course, but I’ve no idea whether it invalidates terms of use, so caveat fructor.

Testing across the CF/Java boundary

For reasons of speed I’m currently embedding Java in Coldfusion code. Given Coldfusion is built on Java, and can instantiate Java objects through createObject("java", class_name), you’d think that’d be reasonably easy. But the boundary between Coldfusion and Java is like the gap between two halves of a broken bone: jagged, bleeding-edged and painful when coerced into heavy lifting.

Java nulls in Coldfusion

The first problem is the Great Coldfusion Error, which is that Coldfusion has no concept of null. At least, it can’t differentiate natively between null and an empty string. So while you can’t explicitly tell if a Java method has returned null, and indeed there’s very little warning of a null appearing in your program’s collection of function pointers, the second line in the below will explode if there’s no associated helper for this object:

<cfset java_object.getAssociatedHelper()>
<cfset java_object.getAssociatedHelper().callHelperMethod()>

If this threw a sensible error in a unit-testing environment I’d have solved the problem quickly, but more of that later. The way round this is to work with Coldfusion’s prediliction for (a) converting nulls to “” and (b) doing all sorts of type-casting on Java objects to integrate Java and CF at the scripting level. Therefore, a check of Len(java_object.getAssociatedHelper()) before you proceed does what you might expect for nulls, yet is also happy when the Java method returns a non-null object.

Errors from errors reporting on errors

The second major problem is that of Coldfusion’s introspection. Coldfusion attempts to latch its metadata introspection methods onto Java objects—including thrown Java exceptions—wherever it thinks is possible. Sadly, that’s far more times than it actually is possible to provide introspection. This is made worse in a unit-testing environment, where introspection is used for reporting purposes. I’m using CFCUnit, which is fairly thorough, but would frequently fail with a generic error that I couldn’t trace at all:

coldfusion.runtime.java.MethodSelectionException: The selected method getDetail was not found.
Stack trace: all from files within CFCUnit

I eventually worked out that Java’s XSLT engine wasn’t happy with an instance of the XSLT/XPath function concat() having only one argument; an error, moreover, that xsltproc failed to catch. The detail isn’t important, though, because you could see a getDetail error anywhere.

When you get this error, don’t bother with cfdump. That tag itself attempts introspection and throws the same generic error. Instead, use cftry/cfcatch to trap the error, and then dump that and quickly abort:

<cftry>
    cfset java_object.thisThrowsAGetDetailException()>
    <cfcatch>
        cfdump var=”#CFCATCH#”><cfabort>
    </cfcatch>
</cftry>

In a struct of structs of structs, of exceptions within exceptions within exceptions, I found it: CFCATCH.Cause.Exception.Exception.LocationAsString carried the precise location of the XSLT error in the file. Easy, when you know where to look.

Exit gracefully: when Coldfusion calls up the underlying Java, often you don’t have all of the usual Coldfusion debugging toolkit at your disposal. This means that any introspection of obscure Java exceptions to see what’s going on will often lead to errors itself, masking the original problem. Let the system throw the error, because the thrown error will eventually bubble up as a Coldfusion struct, with everything else on the way reduced to “safe” Coldfusion data-types, suitable for introspection by cfdump. Although Coldfusion is built on Java, its knowledge of its own foundations is not innate: someone has had to build the CF/Java interface. Don’t expect it to be any stricter or more OO-robust than the rest of Coldfusion.

Subscribe to RSS - interface