« Kill the television, keep the shows | Main | Encouraging passionate readers »
Making happy users
"Make the right thing easy and the wrong thing hard." If designers followed that one clear principle, there'd be a lot more happy users. I'd get a lot more work done instead of struggling with a counterintuitive interface. Writing software would be easier because APIs would simply make sense, with less chance of blowing up at runtime. I could use my car stereo.
That mantra is one I hear every day, from my horse training coach, as the foundation for "natural horsemanship" principles. But I can think of a certain programming language and certain software and hardware vendors that could stand to spend some time hearing my trainer repeat that over and over and over...
Notice that the chart does NOT say, "Make the EASY things easy." It says, "Make the RIGHT things easy." And those things might indeed be quite complex. "I Rule" experiences don't come from doing brainless trivial tasks. (But you can certainly have an "I Suck" experience when trivial tasks are made hard.)
The goal is to make it easy for the user to do the thing he really wants to do, while simultaneously making it difficult or impossible to screw things up. Every screw up, road block, confusion takes the user out of the flow state. It stops him from the thing he cares about, which is NOT how to use whatever tool, device, software it takes to do it.
Yes, I know this goal is dead obvious and "duh." But why are we drowning in products that seem to be made by those who have forgotten this? Or at the least, by those who were unable to do it...
Some examples of "make the right things easy and the wrong things hard" are:
1) A strongly-typed language that stops you from assigning a String of characters (like, "cheese") to a variable that you said was supposed to hold a number (like 42). Or a language like Java with an "exception" mechanism that forces you to acknowledge that bad things (like, the network is down) can happen.
[Yes, you give up other things in exchange for this "protection", so I'm not saying strongly-typed languages are right for everything...]
2) A product whose physical design makes its use obvious and natural, like a jack that fits into only one kind of port, and in only one, obvious orientation.
One variant of this is the concept of affordances, an example of which is a cup with a handle. The handle is said to afford grabbing it--which is the right thing. But a car dashboard with a nice flat surface affords the wrong thing--setting things on it (putting light papers on the dash can reflect on the windshield and make it impossible to see, not to mention what it does to your driving when things go sliding off the dash).
It's still possible to make products whose "correct" use is easy, but which also invite incorrect or even dangerous use. If designers follow only half of the principle ("make the right thing easy") but don't "make the wrong thing hard", then you might have a 50/50 chance that a user will, say, blow up if they he plugs the X into the Y.
3) An API design which exposes the highest-level interface rather than a huge pile of lower-level calls (which could make it way too easy, for example, to call the right things in the wrong order), and whose methods/operations are named well! Half the reason our books sell so well is simply because some of the Java API designers used names that practically beg you to do the wrong thing.
4) A school program that relys on interesting group projects rather than dull, rote memorzation homework. And make those projects something you do mostly in class!
5) And speaking of kids... I try to follow this with the teenagers as much as possible, and one of the simples ways is to have a reduced rule set. The fewer the rules, the harder it is to break them (i.e. the "wrong" thing), and the easier it is to adhere to the ones that are there.
Important note: remember that this isn't simply about making everything easy or dumbing everything down! If I'm working on a video edit, for example, the video edit is where I want my brain bandwidth to go, not how to tell the software that the edit should go here. The point is to make the thing I want to do... the "right" thing... easy, but keeping that "right" thing as complex and sophisticated as it should be. I want my video editing software to give me enormous power, but I want to focus all my brain energy on deciding where--and how--the edit should happen, and have the act of causing the edit to take place as natural as possible.
Every moment I spend trying to figure out the interface--or worse, trying to recover from a terrible mistake the software allowed or even invited--is a moment not spent creating something. Doing my real work.
Games, for example, should not be easy, but the interface in which you play the game should be. The game should allow me to stay in character and not break the flow by forcing me to deal with a user error (as opposed to a "character" error) or by forcing me to stop and look at the manual again...
Also, this does principle/mantra does NOT totally apply to learning experiences, with the exception of tools used to deliver the learning experience. Much of the most memorable learning comes explictly from failures and mistakes--things that did not match your expectations. And I sure don't want my next airline pilot to have had training that supported only the right thing (although many industrial disasters have been linked to cockpits and controls that made the wrong thing easy).
Sometimes we learn through struggle, but for the love of Smurfs, please think long and hard about which things the user should struggle with, and which things should get the hell out of his way.
I'm not saying that I know how to do this well either, but I can sure think of a zillion things I interact with where I think, "why on earth did they name that method in a way that suggests the thing you want but... does the opposite?" or "if they'd only flipped the direction of the switches, they'd be mapped perfectly to the direction of the thing they control (like the "up" switch moves things forward, and the "down" switch moves things back) or "if they didn't want you to sit on this thing, why'd they make it look and feel like a bench?"
Posted by Kathy on October 19, 2005 | Permalink
TrackBack
TrackBack URL for this entry:
https://www.typepad.com/services/trackback/6a00d83451b44369e200d83424871653ef
Listed below are links to weblogs that reference Making happy users:
» Making Happy Users (or Developers) from the Design Experience Weblog
Over at Creating Passionate Users is a great post on getting happy users by making the write thing easy and the wrong thing hard.
The most relevant part to me was "An API design which [Read More]
Tracked on Oct 19, 2005 7:56:49 PM
» Improving my productivity : a full time job??? from Menguy's Blog
Ok, it's time for me to face reality : I have a team, I have too much work, I have to get serious about my productivity.
So let's go web shopping for Productivity secrets ! ... and let's face a second reality : I love to dig for information, try... [Read More]
Tracked on Oct 22, 2005 7:50:56 AM
» Improving my productivity : a full time job??? from Menguy's Blog
Ok, it's time for me to face reality : I have a team, I have too much work, I have to get serious about my productivity.
So let's go web shopping for Productivity secrets ! ... and let's face a second reality : I love to dig for information, try... [Read More]
Tracked on Oct 22, 2005 7:51:25 AM
» Improving my productivity : a full time job??? from Everything and the Universe ... Hum, ok my tech Universe
Ok, it's time for me to face reality : I have a team, I have too much work, I have to get serious about my productivity.
So let's go web shopping for Productivity secrets ! ... and let's face a second reality : I love to dig for information, try... [Read More]
Tracked on Oct 23, 2005 2:58:54 PM
» Users don't care about you from Coding Horror
Seth Godin presented this slide during a recent presentation at Google: Users don't care about YOU. What's the biggest web design mistake of 2004? 1. Believing people care about you and your web site. Why isn't anyone reading our... [Read More]
Tracked on Mar 11, 2006 1:38:35 AM
» How to score on a date with your users (or Set... from StupidApp
Some episodes of MADtv included a returning sketch called Lowered Expectations. The sketch featured weird candidates appearing in a video dating service with the same name.
Application developers often expect their users to perform unrealisitic ta... [Read More]
Tracked on Oct 13, 2006 7:06:10 PM
Comments
Some of what you say here is very similar to the real Murphy's law: "If there's more than one way to do a job, and one of those ways will result in disaster, then somebody will do it that way." (http://en.wikipedia.org/wiki/Murphy's_law)
In adhering to the defensive design practice that can be extrapolated from the law, I find that, when writing APIs, I end up making quite a few more classes than I would if I were just "getting the job done", and some of these have little purpose for existing other than to provide safety.
As an example, if a port number must be between 0 and 65535, then instead of passing port numbers around as 'int's and checking everywhere they were actually used that they meet these constraints, I'd create a Port class, the constructor of which would check the constraints. Then you can pass Port instances around freely, an no other piece of code ever has to worry about its client passing an invalid number. Yes, you end up with a heap more classes this way, but:
- The API is safer
- The API code is simpler to write, because constraint checking in performed in a single place
- Your user's code is simpler to write, because it is obvious from the Type what the constraints are, reducing the need to refer to documentation
- Your documentation load is reduced, because you only have to explain the constraints in one place, not every time the parameter is passed. (Effectively, signatures become self-documenting.)
- Users get "I Rule" feelings: though they might feel like they're creating more objects than usual, they grok everything they're doing, and nothing ever goes wrong.
Of course, creating types for values that are really just primitives with constraints is only one example of defensive design, but the principles can be applied to pretty much every line of code you write.
In case any XML-lovers (and I do mean "lovers") are reading, this is one reason XML is such a poor choice for so many tasks. Once you're inside code, a String of XML is really just a String, and that's that. If the String doesn't contain data in the format that is required, there's not much the code is going to be able to do about it (except to say "your input sucks"). Okay, you might convert it to a DOM, but there's still no guarantees that what's in the DOM is in the form you want, so you have to check its validity at every level where you use it. Conversely, if you accepted a proprietary data model instead of XML, and you make it impossible to construct an instance of the data model that is invalid, then you never have to do any checks, ANYWHERE, because you know what the user's given you is good. Moreover, THEY know what they've given you is good and so THEY don't have to put in code that checks if YOUR checks have failed.
I'm rambling now. :)
In summary:
1. Code defensively
(1a. Use more classes)
2. Stop the XML
Posted by: Graham Lea | Oct 19, 2005 7:43:00 PM
A friend of mine just wrote to me about your topic, saying:
"Warnings against deletion are almost always annoying, but they are possibly worthwhile for the few times somebody really does hit the delete key by mistake."
The problem with confirmation dialogs, though, is that while, in less than 1% of cases, they make it slightly harder to do the wrong thing, in 99% of cases they're making the right thing hard to do! Not a great trade-off. IMHO, Undo kicks Confirmation's butt.
Posted by: Graham Lea | Oct 19, 2005 8:02:34 PM
With regards to item #1, in the 1980s this existed it was called Pascal.
With regards to item #4, this only works when every student is motivated, otherwise you end up with a situation in which one student is forced to do all the work or flunk along with the lazy students.
With regards to Graham Lea's comment regarding XML. This is not XML's fault anymore than Windows OS is at fault because of stupid programs. XML should not be thought of as the markup world's corollary to an application but as a corollary to an environment in which applications may be created.
Posted by: J. H. Shewmaker | Oct 19, 2005 8:21:58 PM
Graham Lea really doesn't understand the purpose or use of XML. More importantly he really doesn't understand how to move data between programs as opposed to within programs. The claims that "if you accepted a proprietary data model instead of XML, and you make it impossible to construct an instance of the data model that is invalid, then you never have to do any checks, ANYWHERE, because you know what the user's given you is good." is demonstrably false. Programmers who believe this produce buggy, unreliable code that crashes. Their code may work when everything is as they expect, but one small change can break it completely.
Just because the API does not allow an invalid instance of the data model to be constructed does not mean that an invalid instance cannot or will not be constructed. Invalid instances of proprietary data models are constructed all the time. This is a routine occurrence. Some times such constructions are the result of bugs. Sometimes they're deliberate attempts to break security. All external input to a process should thoroughly validated, whether it's in XML format or not. Failure to do so has long been a source of crashes in all sorts of products. For instance, you can still crash Word by passing it a document that does meet its expectations for its proprietary data format.
One big advantage to XML is that the XML parser does not assume that everything is OK. You can feed absolutely any bit stream into a parser and get reproducible, predictable behavior. Either the document is well-formed or it's not. Parser behavior is deterministic for both good input and bad input. bad input is detected and reported. While one could imagine parsers for proprietary data formats that were equally solid, one rarely sees such a thing in practice. One certainly doesn't see such a parser written by a naive programmer who believe that just because they've serialized their objects out as bytes it's impossible for anything but well-formed objects to come back again.
Posted by: Elliotte Rusty Harold | Oct 20, 2005 6:24:53 AM
IMNSHO, XOM [ http://www.xom.nu/ ] is a good example of an API that follows this principle well. This has been an explicit guideline since the beginning. As I phrased it in an interview with Bill Venners a few years ago, "More than anything else, I was looking for an XML API that novices—people who were not XML experts—could learn to use quickly, effectively, and correctly. I wanted an API that would not allow them to make mistakes, that would point them in the right direction. I wanted to make the right thing very easy to do, and the wrong thing difficult or impossible to do." [ http://www.artima.com/intv/xomdesignP.html ]
XOM's unusual among APIs in that its design goals and principles have always been right up front along with the tutorials and FAQ lists and JavaDoc. [ http://www.xom.nu/designprinciples.xhtml ] An implicit goal of XOM has been not just to design an XML API, but to teach by example how to design any API.
Posted by: Elliotte Rusty Harold | Oct 20, 2005 7:32:30 AM
I think a lot of developers would like to acheive this goal but doing so usually takes more time. When you are working on your own projects, with no deadline, you have a chance. When you work for a company that just wants you to "get it done", you are not afforded the luxury of thinking it through fully.
Actually, I find the best way of aproaching a clean API is to "get it done" first, and then go back and make it easy to use. You can satisfy the people who ask, "Is it done yet?", while buying yourself more time to clean it up.
Posted by: Rich | Oct 20, 2005 7:50:05 AM
APIs aren't code though. You can improve an implementation later to make it better; but once users are depending on your API, it's very hard to change it or correct mistakes. You really have to get it close to right the first time.
One thing you can do is minimize the API. Avoid committing to anything as long as possible. Expose as few public methods as you possibly can. You can always add methods and classes later, but changing them or deleting them is much more problematic. Err on the side of doing too little rather than too much.
Posted by: Elliotte Rusty Harold | Oct 20, 2005 9:52:26 AM
J. H. Shewmacker wrote:
"This is not XML's fault anymore than Windows OS is at fault because of stupid programs."
I totally agree. The fault is on people who use XML for tasks that it is totally inappropriate for. "When all you have is a hammer..."
Posted by: Graham | Oct 20, 2005 4:56:03 PM
Dear Elliotte,
Firstly, I have to say that I found your post quite rude. My post made assertions about technologies, which, though provocative, couldn't really cause offence to anyone. Your post made accusations about me, accusations which were almost certainly written with the very intent of causing offence, and I find that rude. I am replying because I don't think you understood the context of my post (whose fault that is I don't know) and hence I think you missed the point of what I was trying to say.
Your wrote: "Graham Lea really doesn't understand the purpose or use of XML."
I don't know where that came from, becuase I never stated what I believe the purpose or use of XML is. I only stated that XML is "a poor choice for many tasks" and gave one example of such a task, namely, passing a mass of data into an API as a String. If you believe XML is an excellent choice for every task, then we disagree on its purpose and use.
You also wrote: "More importantly he really doesn't understand how to move data between programs as opposed to within programs."
Again, I don't know how you decided that, because I didn't write anything about moving data between programs. I will admit that, despite using the phrase "Once you're inside code ...", my comments were possibly lacking a clear explanation of the context in which I was speaking. I was continuing a discussion from Kathy's article about authoring APIs that other programmers will then use, and how to make these easier for the programmer to use correctly. Yes, this could be taken to mean inter-application APIs, but that's not what I was writing about. Nevertheless, most of what you wrote (disregarding the parts about naive programmers) was not concerned directly with APIs, but with how "external input to a process should [be] thoroughly validated". I completely agree, but external input wasn't the subject of my post. I was writing about parameters passed into an API.
The point to what I was proposing is this: as you stated, "One big advantage to XML is that the XML parser does not assume that everything is OK." And it's true! XML parsers are particularly good at reporting invalid data. However, if my API accepts XML as input, the XML parser, when it finds bad input, will report errors to the user of my API at runtime. Because of this, they will have to write code that does something about that, just in case it happens. On the other hand, if my API requires the programmer to provide a data model which cannot be constructed to be invalid, the test of valid input can be performed at compile time. The user of my API won't have to write any code to handle errors, because the compiler has confirmed for them that their input is valid.
Finally, in response to what you wrote about "Invalid instances of proprietary data models are constructed all the time", this would be a concern if I was writing about bringing external input into a process, but I wasn't. If invalid versions of my perfect data models are constructed intentionally, so be it. It doesn't really bother me that someone might purposefully concoct an invalid data model and pass it into code I've written in order to make their own program (the one using my API) crash. Certainly, the data model could contain bugs that allow invalid instances to be created. It's my belief that it would be harder to create these bugs (and hence they should occur less often) than it would be to create bugs while traversing, validating and interpreting a generic object model, ala. an XML DOM.
So that's where I'm coming from. If you still disagree with my comment now that I've more fully explained the context, feel free to tell us why. However, I would prefer if you would do so without making offensive accusations.
Sincerely,
Graham.
Posted by: Graham | Oct 20, 2005 9:13:13 PM
Sorry. Graham. You're right. I did not fully understand the context of your comments. Given the expanded explanation I don't really disagree with you. However there's a reason I misunderstood you. You've set up a straw man argument. Nobody actually uses XML to do what you're saying is a bad idea. No one passes strings full of XML as method arguments. The only exceptions are a few XML APIs that offer a convenience method to parse a string as well as a stream. However if an int or an object is more appropriate, then that is what should be and what is passed as the argument. Can you actually point to any APIs that pass XML around instead of objects?
Posted by: Elliotte Rusty Harold | Oct 21, 2005 5:40:31 AM
Make it easy to input the right thing, and difficult to input the wrong thing.
Tadam! We have Dasher (http://www.inference.phy.cam.ac.uk/dasher/ )!
Posted by: Tomer Chachamu | Oct 23, 2005 8:21:43 AM
With regards to making things save and easy, Adobe has some very good features:
InDesign is great in that respect - unlimited undos as long as you keep the file open, even after hitting save during a session.
The history palette in Photoshop is also nice because you can exactly see what you have done and undo (and redo it again) serveral steps at a time.
Posted by: Jens | Oct 24, 2005 3:15:33 AM
The comments to this entry are closed.