home Another Picture
21 May 2009 Network Computing is hard

I used to work for a company called Tarantella and we had a great idea: "desktop computing", by which we meant PC's running big applications from Microsoft, had turned out to be a real headache. How much better would it be if we hosted applications centrally and projected their user interface over the web using a clever Java applet? People would only need a web browser, not those clunky, expensive PCs and all the apps could be administered centrally. We would make our fortunes and retire to Monaco.

Turns out that didn't happen. Also turns out the idea wasn't that original. People had been having it for about thirty years and lots of people were having it at the same time we were, notably our two biggest customers: Sun Microsystems (who later bought the company) and Oracle (who later bought Sun Microsystems).

Sun and Oracle hoped that network computing would let them "commodotise Microsoft". If all the applications are running on a big server in the sky then the client machine stopped mattering. More importantly, it stopped needing to run Windows. If all this sounds familiar you've probably read one of the blog posts guessing at Google's master-plan. It goes something like:

  1. Re-write Office in HTML
  2. Host it and everything created with it at allyourbase.google.com
  3. Adverts
  4. World domination

This is given credence by people who should know better because, well because it's Google. And they've got all those smart people. And that geyser of cash. But the truth is that people didn't really like the idea of a thin client ten years ago and they don't really like it now: they don't like the crappy experience of the applications, they don't like giving up control, and they don't like giving up their data - if your data is on Google's servers then it belongs to Google, not you.

Network computing isn't a wrong idea it's just not going to help you unseat Microsoft. They more than anyone else would like applications to move to the web - then they could start charging subscriptions and make some real money. The problem is that network computing is hard. Look at Google Gears or HTML 5 and the consensous is that once you've got SQLite crammed into the browser for offline storage and the canvas tag for "vector graphics" then collaborative, nomadic, mutli-sychronous network applications are just a simple matter of JavaScript. I think lot of people are in for a nasty shock.

Consider what network computing will have to offer to be adopted:

  • A UX experience that is as good as desktop applications. HTML applications won't cut it. HTML 5 applications won't cut it. Delivering HTML applications that have the same UX as their desktop counterparts is either impossible or massively more work.
  • Seamless adaption to connectivity modes. Connectivity is not ubiquitous and, even if it was, people's desire to be constantly connected is not ubiquitous.
  • Distributed, always-available storage. Client-server isn't going to work: it's inherently a single point-of-failure, single-point-of-congestion architecture. Tolerable for websites, not so good for living documents accessed by mutliple devices and multiple participants. And while we're on the subject...
  • ...multi-synchronous concurrency. If a document is an artefact in the network it will be accessed concurrently by many different devices and many different collaborators. You could have one copy each, but how is that better than what we have now? To be compelling, many participants must be able to work fluidly on the same artifact. Since we also can't depend on a network connection, we can't depend on getting a global lock (even if we wanted to) - we require a multi-synchronous concurrency system.

This are non-trivial goals that touch just about every area of systems development; it's not as easy as switching on contenteditable and pretending you've made a word processor

20 May 2009 Systems Programming Languages?

What would people recommend as a good systems programming language in 2009? I'm writing the systems components of metro on OS X which means lots of good old UNIX systems programming.

The obvious choice is C but after years of being cosseted with Java and .NET. I couldn't face going back to a macro-assembler. I need a language that:

  1. Has a garbage collector. Not reference counting, and not the Boehm-Demers-Weiser bolt-on GC that leaks more than it collects if you are not just as careful as you would be with raw malloc.
  2. Compiles to native code. Depending on a VM when writing UNIX systems software just seems wrong. You can get away with it in Windows when the CLR is so tightly integrated. But not on OSX and Linux.
  3. Has a simple foreign function interface. I need to wrap existing sys calls but I don't want to spend forever doing it or have it be so complicated I might as well write the whole thing in C in the first place.
  4. Is productive. GC alone probably makes you an order of magnitude more productive than when you have to do manual memory management. I want a language that allows me to write correct code fast. C is not this language. Neither is C++.
  5. Is source compatible across Linux and OS X. I'm flexible on this but I'd prefer to target "Unix" and "Windows", not "Linux", "OS X" and "Windows".

This seems to leave either Ocaml or D. I'm going to write the Windows system components in F# so Ocaml is the obvious choice - it's succinct and very expressive and hopefully there will be a lot of code sharing between an Ocaml implementation and an F# implementation. The more I look at D though the more I like it: it is mature, seems to have an intelligent community and is focussed far more on practical systems programming than the rather academic Ocaml.

I have a pair of co-operating daemons to write for this project. One will be done in Ocaml, one in D and I'll share my experience. Of course, if anyone knows any languages I've missed, I'll be happy to hear about them.

19 May 2009 Visual Design

Beautiful things work better. Donald Norman, in his 2004 book "Emotional Design" recounts a study by researchers Masaaki Kurosu and Kaori Kashimura to investigate how aesthetics effects the apparent usability of a software artefact - in this case the interface to an ATM machine. Kurosu and Kashimura found that subjects of the study consistently rated the apparent usability of an interface higher when it was prettier - a finding later duplicated by Noam tractinsky in Israel.

People really do feel that aesthetically pleasing interfaces are easier to use; regardless of whether that is actually the case. Note that in Kurosu and Kashimura's report it was aesthetics and apparent usability that was strongly correlated, not inherent usability: people felt that the prettier interface was easier to use, which really is all that matters.

Norman uses the work of Alice Isen to try and explain this phenomenon. Isen carried out a number of studies in how emotional mood affects problem solving ability and found that "happy" people are more effective in finding alternate solutions and are therefore more tolerant of minor difficulties than "unhappy" people. People she gave a slice of cake to solved brain teasers better than people she didn't. Norman ties this in with recent research about how emotion and cognition are interlinked:

"Everything we do has both a cognitive and an affective component-cognitive to assign meaning, affective for assigning value." Norman 2004

To paraphrase: Pleasant looking interfaces make people happy, happy people relax, relaxed people are better at solving problems. If your interface makes people better at solving their problems they'll think your interface is better.

So make it pretty.

18 May 2009 Eliminating Exercise

Exercise extra interaction that does not contribute to a user's goal and therefore interrupts the user's flow. Some exercise is unavoidable, but an excess of it usually indicates that the software has poor navigation - it is difficult for a user to find the information he is interested in. Some tips for eliminating exercise are:

  • Don't force the user to go to another window or page: especially to do something that affects his current window. With web apps, it is tempting to map different stages of the underlying software to different pages. However, the visual dislocation involved often shakes the user out of his flow. Ajax techniques can be used to load sub-pages into the current view without replacing the whole display.
  • Don't force the user to remember things: Whether it's user settings or where he saved a file, the system should remember for the user. Computers are good at remembering, people are not.
  • Try to allow input where you have output: For example, if you have a view that displays the user's settings you should allow the user to enter a mode whereby he can edit those settings in the same view. On the same issue, you should not force the user to complete a form unless absolutely necessary. Not badgering the user is more important than keeping the database tidy.

The easiest way to improve navigation is simply to reduce the number of places the user needs to go; and if the user does need to go somewhere, you should bring try to bring that place to him. Some tips for improving navigation are:

  • Keep the number of pages/screens in the application to a minimum: preferably only one.
  • Keep the number of panes within a page to a minimum: preferably no more than three - and hide panes that are not in use. Try to minimize any necessary scrolling.
  • Provide signposts: fixed, persistent elements within a page.
  • Provide overviews: indications of the user's current location within the wider context of the application. The "breadcrumb" trail commonly seen on websites is an example of this.

Finally, you should try and "inflect" the interface - organise it to minimise the most common navigation path, and thus reduce exercise and keep the user within his flow. Inflecting the interface usually means organising it according to three attributes:

  • Frequency of use: the most frequently used elements should be the most prominent in the interface - that is, the most immediately within reach. The less frequently used should be pushed deeper into the interface.
  • Degree of dislocation: this is the amount of visual change introduced in the interface by activating the specific function. you should either hide these functions deeper in the interface or move them away from the commonly used functions.
  • Degree of risk: if your function erases the user's hard drive then it should not be prominent in the interface. Move any destructive operation (that does not have a compensation operation) deeper in the interface.
17 May 2009 Orchestration

A good interface should be invisible. Orchestration is the process of making sure that all the elements in an interface work coherently together, without any sour notes that will shake the user out of his flow. Unfortunately, there are no fixed rules for making a well orchestrated interface - it is a function of the user's activity and the context in which he is working. HIGs, UI manuals published by Microsoft and Apple, are useful but will not tell you how to create a harmonious interface: only experience and feel will. However, there are some useful guidelines:

  • Less is more: If the user could have his problem disappear without using any software, indeed without making any effort, he would. This is the ideal that you have to approximate. Using your software will be a chore no matter how good it is so try to minimise the amount of time the user has to spend with it. When you think you have finished your design, iterate and iterate until there is no more to take out.
  • Don't design for corner cases: programmers have to be paranoid about corner-cases; if a pointer is non-null 999,999 times an null 1 time a program will still crash. Unfortunately, when programmers design interfaces this reflex is carried across and possibilities are often presented as if they were probabilities. Dialogs and controls that deal with edge-cases and are used once a year sit side-by-side with controls that are used several times a day.
  • Reflect status: Your software should look busy when it is busy and quiet when it is quiet. Moreover, when your software is busy it should provide unobtrusive, modeless feedback about what is keeping it busy.
  • Don't report normalcy: It may be important during development to know that your software is behaving as expected, but it is not important to the end user. Success should be the normal outcome of any operation performed so only interrupt the user when the result deviates from this (i.e. the operation fails). Even then, you should only report serious errors - usually errors that may result in loss of data. If an operation is simply taking a long time then display an in-place progress indicator instead. Never pop-up a modal dialog to report an operation has been a success. No-one is going to give you a medal.
  • Don't interrogate: Asking questions is not the same as providing choices. Interrogation of the user is the most prominent artefact of the engineering-oriented approach to interface design. Wizards are the most objectionable manifestation of this. From a systems point of view wizards seem like a perfect UI solution since the engineer gets to treat the user like a troublesome disk-drive from which he can 'read' strings and ints and floats when his system needs them. This is the opposite of good interaction design wherein the user is in the driving seat. Instead of interrogation, provide a reasonable set of defaults and allow the user to modify them.
  • Hide the ejector seat levers: For every destructive operation in the software try to provide a compensation operation that will undo the damage if the destructive operation is triggered accidentally. If you can't provide a compensation action then make sure the user cannot trigger the destructive operation by accident - hide it away in a sub-panel. Either way, you can put in all the "Are you sure you want to delete..." confirmation boxes you want, no one will ever read them.
16 May 2009 Flow

The psychological state of flow occurs when people are able to concentrate fully on an activity without interruption or peripheral distraction. It is this state that a good software design seeks to generate. Software that successfully induces flow becomes transparent to the user's thought process and usually exhibits the following:

  • It follows mental models: Users do not need to know the inner details of the software to use it. The user's mental model is a cognitive shorthand for how a system works "one that is powerful enough to cover their interactions with it but which doesn't necessarily reflect its actual inner workings" [2] Interfaces should reflect this mental model rather than the structure of the software itself (known as the system model).
  • It does not converse: Users want to instruct a piece of software, not have a conversation with it. Don't engage in a dialog with the user and don't halt an activity to demand answers from him. From the user's point of view it is he who should be asking the questions and the system that should be answering.
  • It keeps tools close at hand: Hunting around an interface for tool will break the user's flow; when a user engages in a specific task, the tools that he is likely to need should be brought to him.
  • It provides modeless feedback: feedback is modeless when it is integrated into the normal flow of interaction. Modeless feedback is preferred since it does not stop the user's activity. Pop-up dialogs should be avoided.
15 May 2009 Design as Conversation

Without effective design engineers tend to ship products made in their own image - heavy with "expert" features (where the definition of expert is someone suspiciously similar to the engineers themselves.) This is entirely rational - what other model to the engineers have to go on?

Moreover, after this expert-heavy first version is put out to a bad reaction it is festooned with features for the "beginner" - training wheels such as wizards and dancing paper-clips. We wind up with software that has lots of features for the minority of experts, and lots of features for the minority of beginners and barely any features for the vast majority of intermediate users. Good design is about inverting this profile.

14 May 2009 Interaction Design

"The intractability of the software construction process - particularly the high cost of programming and the low quality of interaction - is simply not a technical problem" Alan Cooper

My colleagues at BNP hated the software they had to use. Whether it was store-bought or developed in-house they found it buggy and frustrating and stressful: eight-hours-a-day five-days-a-week. Was this down to stupid programmers making bad software? Maybe, but unlikely. Much more likely is that the people responsible for originating the software - the product teams and executive teams - did not have the tools to articulate exactly what the software should be. Without clear direction programmers cannot create clear software.

The business people staffing executive and product teams are schooled in a system designed to maximise profits on the manufacture of physical objects, usually by reducing variable costs - the costs that vary with each unit shipped. They reflexively treat software production as a variable cost and, with the best intentions, set about trying to reducing it.

Unfortunately, this is a catastrophic strategy both business-wise and in terms of software quality. Software production is not a variable cost - in fact software has very little variable costs, once it is written you can reproduce a new unit for the cost of pressing a new CD. If your software is downloaded over the internet the cost of "shipping a unit" is effectively too small to measure. When execs think they are minimising variable costs on software development what they are actually doing is minimising the quality of the product since programmers not only do not know what they are making but are always given too little time to make it.

This is the situation that interaction design, and software design in general, should remedy. Good design should provide a clear picture of what the software does and who it does it for. Not in terms of a floating check-list of "features" but by defining a target user, defining his goals, and enumerating the interactions the user will have with the finished software to achieve those goals.

13 May 2009 Software Design

I'm going to reboot this blog by serialising a guide to interaction design that I wrote for my old employers at BNP Paribas, and recently gave as a lecture to my new employers at True Knowledge.

It's a sobering thing, as a technologist, to go work for an investment bank. Cambridge can be a rather cosseting techno-utopia, steadfast in its conviction that software can make the world a better place just as soon as we've worked out the bugs. That is a fine ideal, and not one I disagree with, but at any software firm you are insulated from the people you are convinced you are helping and this can lead to you not really helping them at all.

BNP Paribas staff are submerged in technology, utterly dependent on it, but their relationship with it viers from apathy to irritation to red-faced rage - never satisfaction, certainly not enjoyment. It is good, if not easy, for a technologist to work in such an environment. You either give up or you get focussed.

As a technologist, I knew that software should be making their lives simpler and even happier, but it was not, and that is not a story isolated to investment banks. Why is most software so buggy and frustrating to use? Are programmers just too stupid to create good software?

Of course not. Programmers are smart people but most of the time they are working in the dark on something that has never been designed. There is even a disturbing, unspoken, notion in development circles that software cannot be designed and developers must just get used to this fact and work around it: processes with important sounding names such as "SCRUMM", "Agile Development" and "Extreme Programming" have evolved to give a veneer of intellect to this idea.

I distrust the notion that the best we can do in software development is throw "features" against the wall to see what sticks and my experience at the coal face of BNP has only convinces me that a proper design phase is essential in any software endeavour. But how do we do it?

Software design, by which I mean the wholesale design of a software artefact, not just the design of the internal technical architecture or the external visual UI design, is a discipline still in need of definition but perhaps a good start is with the current notion of _interaction_design.