Sunday, July 20, 2008

Making me think about usability

That's Funny by ehpien from flickr (CC-NC-ND)

I've just finished reading "Don't Make Me Think" by Steve Krug, which claims to be some sort of a web usability classic.

What I liked most about it was the chapter about user testing. The short summary is - test early, test often, 3 randomly selected people with one hour per person is the best cost to benefit ratio for a round of testing, don't bother with detailed written reports, just fix the worst problems and do another round later.

Other than that I didn't like the book that much. I see how it might have been useful in the Web 1.0 days, but its focus just feels wrong. It seems to think that the most important part of a website is its navigation and so spends most of the pages discussing it, but how relevant is navigation when vast majority of users come from Google, or some other kind of search, or direct links, or RSS, or even bookmarks, and people reaching your content by patiently clicking their way though from your homepage are a tiny minority?

Most blogs, wikis, and web apps don't even have real navigation structure, and they're the part of the Web that's growing fastest. Even Amazon which the book glorifies as The Paragon Of Web Usability seems to have mostly given up hierarchical navigation and now exposes search and personalized recommendations as the most prominent means of getting around.

So the book has some useful content but is hopelessly outdated and unfocused. 3 stars out of 5 if you numbers.

Usability



As the review made a rather short blog post I'm going to conclude it with somewhat controversial remarks on Web usability. By the way if what you're saying doesn't cause any controversy then
  • you've just discovered some new universal truth (only happens in maths),
  • or you're just repeating some nicely sounding but ultimately meaningless slogan like "use the best tool for the job",
  • or most likely - nobody reads your blog.

So controversy and exaggeration to get the point across are good.

First, accessibility is overrated. I've seen so many people performing magic rituals supposed to make their websites "accessible", like anal adherence to "web standards" even to the point of using XHTML, making sure the website works without Javascript and/or CSS, making unique text in headers and so on. Two things they never do are measuring how many users are actually going to use accessibility features, and testing accessibility in realistic settings (like with a screen reader or Braille terminal), and these two things seem to me to be the only ones that would matter.

Accessibility zealots also often claim that:
  • websites done in some "right" way are somehow magically accessible,
  • making a website Google-friendly is somehow the same as making it accessible,
  • and that you're legally required to spend as much effort making your website accessible as necessary.

All of which are bollocks.

I think this misguided thinking is caused by a combination of two reasons. The first is the good old web standards zealotry. Seriously, why people get so emotional over some badly written documents without even a reference implementation or a serious test suite? Even FreeBSD vs Gentoo and Emacs vs vim (by the way correct answers are Ubuntu and TextMate, and 2 spaces) flamewars aren't as heated as the ones about web standards.

The second reason is a certain kind of a reality distortion field. There are many kinds of web sites on the Internet. The kind that used to be most popular are "text-based content sites", where users come to read static stuff. The reality distortion field makes people think this kind of websites is still dominant, but it's not. Looking at Alexa's top list it's difficult to find a single text content site other than Wikipedia. Everything is some sort of a web app, or video site, or social networking site, or anything but text content.

Now I mostly agree on one point - making text content site reasonably "accessible" is not very difficult, and to some extend correlates with things you need to do anyway to support Google, mobiles and so on. I will still laugh at people who think they can get "accessible" without genuine testing (if accessibility checklists worked, why won't they write IE6 accessibility checklist, wouldn't that be so much easier?). But the problem is something else - only reality distortion field of epic proportions can make you think most websites are still text content.

In a way it's similar to DBAs being deluded that most SQL databases serve as integration point between multiple independent codebases (and so need stored procedures, triggers, complex constraint enforcement and business logic on database side etc.) when in reality 99% of them are little more than persistent store for a single app and these features are more harmful than helpful.

So how about the vast majority of web sites that are not just about text content? Oh sure, you can make them accessible. It's just going to be long and painful process with very little payoff, and which won't ever end in a full experience parity unless your application is very very simple. And you know what - screw the blind people! The largest discriminated group are people who don't speak English as their first language. It's about 95% of all people, a lot more than 0.6% who are blind. Why don't they care adequate attention? It's an insane misallocation of resources if you care about the blind but don't even have a German version of your website (and versions in at least 50 other languages). Blind people are more or less as important as Welsh localization, and you're probably not caring much about that, are you?

Forget about experience parity, no mater what technology. Vision is the most important of human senses and the only way to make non-visual interface work as well as a visual interface is by horribly dumbing down the visual one, hurting 99.4% of your users who can see. Try getting somewhere with a spoken Wikipedia article about London instead of a map. Or reading long lists of numbers instead of a graph. Or playing Portal with a screen reader. Or for more relevant example using "basic html" version of Gmail instead of the real thing.

My second point, video websites should not autostart their videos. Haven't they heard of tabbed browsing? To open multiple tabs with YouTube videos you need to:
  • open the tabs,
  • go to first tab,
  • wait until the video partially loads and starts playing,
  • click pause (you cannot click pause earlier),
  • then do the same for the all other tabs,
  • and finally go to the tab you want, rewind the video and click play.

Couldn't they at least detect they're in an inactive tab somehow? Firefox seems to be sending onfocus when a new page is opened in a new tab or when you first switch to an inactive tab - not autostarting until you get onfocus sounds like a good start. Making pause button work before the video loads would also help a lot. Or are there perhaps some Firefox plugins or Greasemonkey scripts to get rid of video autostarting? The only thing it's good for is rickrolling people.

The third thing, stop using lowest common denominator fixed width layout. CSS lets you do many things that weren't possible with tables, but some of them are just stupid. More and more people have widescreen these days. Widescreen means wide but short. OS and browser usually take a lot of space on top and bottom of the screen, but not on the left and right, making screen aspect ratios even more extreme. So there's lot of space on the screen but it's mostly horizontal, and what do so many designers do? Completely ignore half of the available space, and then fill the rest with ads and other crap so the useful content is taking a tiny fraction of what it could take. I know making "design" work in multiple sizes is harder, but design isn't what users are interested in. They came to your website for the content, not to revere your mad design skills.

And the last thing, CSS compatibility with IE6 is a waste of time. JS compatibility became an almost non-issue thanks to jQuery and other JS frameworks. So why not use a JavaScript solution like ie7-js and be mostly done with IE6 CSS too? Some people won't like the suggestion of depending on JavaScript, but IE6 does run JavaScript just fine, and no other browser (Google spider, mobiles, text browsers etc.) is going to be affected in any way, so what's the big deal?

OK, if JavaScript dependency on ie7-js still makes you feel uneasy, couldn't we at least somehow use for automated testing? Run the website with and without it, get a list of differences and suggestions based on how ie7-js fixed them. Seems like a lot better way than manual debugging. But I'm not a Windows guy, so don't expect me to code that.

The New Law of Demeter

Baby cat by fofurasfelinas from flickr (CC-NC-ND)
Once upon a time I've stumbled upon The Law of Demeter, which says that you can only call methods on:
  • self
  • self's fields
  • current method's parameters
  • objects you created
  • global objects

It's often shortened to never use two dots in a row. The implication of this law is that if you legitimately obtained order object, then order.customer and order.customer_name are valid, but order.customer.name is not.

At first I interpretted this law literally and (just like you did a moment ago) reached the obvious conclussion that the idea is total bollocks - writing (or even worse autogenerating) thousands of proxy methods like def customer_name; customer.name; end or even delegate :name, :to => :customer is not going to improve quality of your code at all.

It sounded like thousands of those little silly rules like "Use factories instead of constructors" that Java code monkeys make up all the time so they can think "If only everybody adhered to these rules, Java coding would be just fine" and keep blaming other people for their problems instead of blaming themselves for being so daft and sticking with Java. The same Java monkeys don't even adhere to their rules, and so Java coding isn't fine, but even if they did adhere it wouldn't help as you cannot fix technical problems on cultural level. So I forgot about the whole thing and moved along - another stupid rule for people who are afraid of the code.

Of course if this was how the story ended I wouldn't even bother blogging about it. On the contrary, I had a sudden realization - sure, the Law of Demeter has many obvious counterexamples of perfectly valid code that's illegal according to it, and would be made much worse if it was enforced. But most of them go away once it's subtly reinterpretted. There's a loophole for "objects you created" which doesn't have to mean "object you created by ClassName.new" - every object that was created at your request and the producer doesn't hold any reference to it any more can be considered to be "created by you" (old objects whose ownership was relinquished to you should also qualify, but this is a very rare case and I'm not going to talk about it any more). Let's call this interpretation "The New Law of Demeter" and apply it to an exaggerated example:
message = hash.keys.sort_by(&:abs).map(&:to_s).join(" ")

Naively interpretting the Law of Demeter it should not only be illegal but sent straight to the Guantanamo Bay - there are 4 explicit and 2 implicit dots in it, all in a single line.

But this is perfectly sensible piece of code. It does something useful and it's definitely far saner than hash.keys_sorted_by_absolute_value_stringified_and_joined_by_spaces, hash.keys_sorted_stringified_and_joined(&:abs, " ") or any other Demeter transmogrification I can think of.

But why is it really illegal? Every single dot creates a fresh object - Hash#keys does so, and so do Array#sort_by, Numeric#abs, Array#map, Numeric#to_s, and Array#join. The code doesn't violate the New Law of Demeter in any way!

The Law of Demeter is much more permissive when interpretted this way, but I wouldn't stop here yet. I really think order.customer.name is perfectly sensible even if customer is owned by the order. What counterargument some proponents of the Law make? Mostly that it makes customer's name harder to mock if you ever want to make order return customer name not tied to any genuine customer. But why should Order#customer be limited to returning real Customer objects? How about making it return read-only snapshots of current customer? This is exactly how order.customer.XXX is used vast majority of the time. As snapshots don't need any write behaviour, it's very easy to return a snapshot with overridden #name, and as a customer snapshot is a fresh object you've just created, you are allowed to call any methods on it you want.

So let's pretend that every time you do order.customer you really mean order.customer_snapshot, and code like this becomes legal:
puts order.customer.address.postcode

The New Law of Demeter lets you do a lot more than the old, including legalizing almost all sensible view code, but it still delegalizes a lot of dubious code. For example code like this is definitely not legal, as it expects read-write objects, not fresh snapshots:
order.customer.first_name = "Bob"

This is also not legal, as snapshots should be fresh objects and not be auto-updatable:
customer = order.customer
order.add(item)
puts customer.balance # item included or not?

but it can easily be transformed into this legal code:
order.add(item)
customer = order.customer
puts customer.balance # item definitely included

Reinterpretted this way, the New Law of Demeter is really useful at detecting code smell. Unfortunately it also becomes much more difficult to apply, as you need to look not only at the syntax but also at the sema an object to which the original creator still holds a reference; and does the method affect state or does it have snapshot access semantics and so on. I'd love to see a Demeter lint which would try to check compliance with The New Law of Demeter in a meaningful way.

Monday, July 14, 2008

All the Firefox extensions you need

I love my tail! by play4smee from flickr (CC-NC)

Here's the third edition of my insanely popular (who am I kidding, people only come here for angry rants and Ruby tricks) series on all the Firefox plugins you need to turn it into a useful browser.

The Firefox world has changed a lot since the first (May 2006) and second (May 2007) editions of this list - and now with Firefox 3 released an update is very much in order.

The Web the way it's supposed to be


Internet out of the box is crap. It's full of ads and sites which require registration, bookmarks disappear when you switch computers, and Google Images links to tiny thumbnails instead of images it's supposed to. All these annoyances can be cured by aggressive Firefox plugin therapy.

First install Adblock Plus. Filterset.G Updater isn't recommended any more, so you can skip this step. Adblock Plus blocks vast majority of ads of all kinds (flash, banner, text, css pseudo-popups etc.) without disrupting too many websites (in fact crappy ads are much more likely to disrupt a website than Adblock Plus). The reason it works so well is that on almost all websites ads are provided by a third party external request (image, iframe, script etc.), so it's very easy to tell the difference between website content and ad content. Technology used by Adblock Plus wouldn't really work against other kinds of unwanted content like malware, spam, porn etc., because there's no first party-third party separation in their case. It also won't that well work against ads on search results pages, but these tend to be less obnoxious. The only website of any use that I found not working with Adblock Plus was TubeJP. If you need to fix TubeJP or any other website, try adding "@@tubejp.co.uk" exception to your Adblock Plus's list (@@ means exception) and reloading the page. It should work. Or you could completely disable Adblock Plus from Adblock Plus Preferences, and reenable it when you're done.

Once you've done that let's move to the next problem - websites which require registration. I'm getting an impression that they are fewer in number these days, but in case you find one it's good to have BugMeNot extension installed. Just right click on the form, select "Login with BugMeNot", and the annoyance hopefully goes away. Or not if they're good at deleting shared accounts, as YouTube seems to be. If it doesn't work you can always register with a disposable email address and crappy random data. They usually only check that the email address is routable and you selected that you're older than 18, so happily tell them you're Albert van der Putin, a 95 year old gold farmer from Thailand, living at 1337 Eric Cartman Street, New Buenos Aires, post code 12345 or whatever. It's in their best interest to let you do that, as this kind of crap is easy to filter. If they actually try to verify that what you're filling in makes sense then just google some realistically looking address and phone number and use them to make their lives more difficult when they try to analyze their user data.

Now let's make your bookmarks work. You probably already have a del.icio.us account. If not, create one before you go on reading this post. Then you could test your new del.icio.us account by bookmarking this blog for instance. del.icio.us Firefox extension disables browser-side bookmarks and replaces them with server-side bookmarks that you can access from everywhere and share with others. To bookmark something press Control-D, and most of the form will be prefilled for you - URL, page title, and even suggestions for keywords based on how others tagged that page. It's just an insanely fast way of creating del.icio.us bookmarks. For accessing bookmarks you can use methods provided by the plugin but personally I always type http://del.icio.us/USERNAME/TAG in URL bar instead. Much faster if you know what you're looking for.

The next plugin requires some work to get it right, but as you'll spend significant portion of your online time with Google services you might want to use it anyway. It's CustomizeGoogle and it's used to (surprise) customize various Google services. There's a nice two-minute screencast showing some of the basic options, and there's a lot more of them.

Some of the things you might want to enable are:
  • Disable ads on services where they don't make much sense. You can leave them on Google Search but disable on Google Images etc., any way you wish.
  • Switch sensitive services like Google Mail to SSL.
  • Make Google Images results point directly to images instead of the thumbnail+frames page.
  • Make search results AJAX-stream. Especially important for Google Images.
  • Add links to other search engines on search results page. I mostly use it to search Wikipedia.
  • Hide Google Mail spam counters and invite box, which are simply annoying.
  • Filter your search results.
  • Enable Google Suggest.
  • and much more.

Google won the search engine wars, the web mail wars, the image search wars, the map search wars, and for that matter almost any wars it got into, so we're spending a lot of time with Google things that it'd really be a horrible waste not to customize them a bit.

Making Firefox a better browser


The Web just became a better place, so let's apply a few fixes to the browser. First let's get rid of the downloads window, which is an ugly remnant of the pre-tabs days. Opera uses a downloads tab which is a far better solution than a window, but we can do even better than that with a Download Statusbar. If Firefox developers won't incorporate something like that in Firefox 4 that's a definite proof they're really a sleeper cell of al-Redmont and they should be ie6boarded until they start to cooperate.

Crash recovery (aka session management) was greatly improved in Firefox 3, but it's still better to use Session Manager which saves sessions also on exit, so you won't have to killall -9 firefox as a crude "Save Session" button.

Just these two extensions plus the ones I mentioned in the previous section are probably sufficient for most users. To add some finishing touches you may want to install ColorfulTabs for color-coded tab labels (switch to URL-based colors and fading 7 for best results), Fission for Safari-style progress bar integrated with URL bar, Tabs Open Relative for new tabs that open next to the current tab instead of the end of the tab list, and ReloadEvery for web site autoreload functionality like in Opera.

User Agent Switcher lets you pretend you're using some browser other than Firefox. Fortunately web sites requiring Internet Explorer are pretty much thing of the past. The only one I've had problems with in the last year was one supporting Firefox 2 but not Firefox 3 beta, what was really stupid, but they've fixed it already.

Unfortunately at the time of writing this post TinyURL creator for Firefox. didn't support Firefox 3. That's a shame as it was a very useful plugin.

Web development


If you do any web development at all, and as you're reading this blog there's a high chance you do, you absolutely positively need to install Firebug. It's more important for web development than Ruby on Rails, TextMate, jQuery, and Selenium taken together. Of course that's no reason not to use Ruby on Rails, TextMate, jQuery and Selenium together with Firebug. Here are some screencasts to get you started.

In addition to Firebug there are a few small plugins you might want to install, like Web Developer which provides a right click menu with some extras not included in Firebug, like manipulating cookies, disabling Javascript and so on. Nothing really big, but having all these small nitfy functions in one place is useful.

If you're using Windows you may want to use IE Tab. This of course doesn't give you Firebug for IE, and unless it lets you run multiple versions of IE simultaneously (does it, I have no way of testing that?) it's not even that useful for compatibily testing.

XPath Checker helps you write XPath expressions for page elements and therefore prepare some test cases for view layer unit testing somewhat more easily.

Web 2.0 Integration


CustomizeGoogle, del.icio.us, and BugMeNot are technically about website integration but I don't really think of them this way - they're just too fundamental to the way the Web works.

If you use Twitter like I do you will probably want to install Twitterfor extension, which is very simple and gets Twitter integration done right.

If you have too much time to waste you will want to install StumbleUpon plugin. Just vote up or down a few pages and you'll start getting your own personalized reading list. By selecting the right categories you can even use it for personalized lolcats or porn or lolcat porn.

If you have a Gmail account, Gmail Notifier is very useful for getting notifications.

Total Conversion


Some mods are standalone applications living inside Firefox, for things like IRC, BitTorrent, FTP and so on. They're usually not as good as the best standalone applications, but are fully crossplatform, so if you're switching your systems often you may want to take a look at them anyway. The only one I've used extensively is ChatZilla which seems to be the best cross-platform IRC client out there.

Non on the list


I've heard that Greasemonkey is absolutely awesome, but I never quite got to trying it out.

NoScript seems to be quite popular, but it didn't get on the list, as I really don't see a point of using it for web browsing (what next, NoCSS, NoHTTP1.1 ?), and for compatibility testing Web Developer extension already provides this functionality. By the way it doesn't provide you as much privacy as you think, plain CSS can leak your browsing habits quickly enough.

One plugin that you should definitely disable are "Ubuntu Firefox Modifications". It's automatically enabled by default on Ubuntu and the only thing it seems to do is breaking right click functionality on many websites.

Final words


That's the list of Firefox plugins I'm using. Of course your needs are different, so your list won't be exactly the same. I hope you've found some suggestions in this blog post and I'd love to hear back from you on how you're using your Firefox.

As Firefox is changing quite rapidly I'll probably post an updated list in a year or so, perhaps incorporating some of your suggestions.