Friday, December 14, 2007

Interface Design: APIs as a User Interface

This article closely parallels Interface Design: World of Warcraft vs. Excel. In that article, I claim that UI designers can learn from game designers. Now I'm going to claim that library authors can learn from UI designers.

Library authors write code that is used by other programmers. Their interface is called their API, and, like a GUI, it is all the user has to see in order to use the product. An API doesn't look much like a GUI, of course. It is a highly specialized UI that can only be used by someone trained in their use.

Usability concerns are certainly important for APIs. If a programmer doesn't understand your API, then they will not be willing to use all of the features that you put into the library. They'll have bugs in the corners or the library that they thought they understood, too. Confusing APIs directly contribute to unreliable code and lower programmer productivity.

What can library authors learn from usability experts? This isn't as stupid a question as it sounds. Usability experts have figured out a lot about how human brains learn how to do things. Programmers have brains that work almost exactly like everyone else's brain. (I may get flamed for that sentence, but I'll warn you ahead of time that I can defend it.) There may be something worth learning.


Patterns can help a lot. If I'm on a web page, my brain has been trained to try to click on underlined text. This is a valuable pattern that usability folks can use when they want users to click on some text. Likewise, programmers like patterns.

If I'm using a modern C++ library, and I want to get access to a collection of items, I'll try to grab an iterator range using functions called "begin" and "end". Once I get those iterators, I know exactly how to access the contents of the collection. My brain can then abbreviate a lot of different tasks as "this class acts like an STL collection". Suddenly, getting access to a collection in a library becomes easy.

Programmers have been trained to see and use a wide variety of patterns. Generally a framework will define the patterns that users will get trained on. Ruby on Rails, for example, trains users to get access to items referenced through foreign keys using the name of the table that you're trying to get to. You can write a rails library without doing this, but it's something extra that users of your library will have to learn. Instead of thinking "table A has a one to many relationship with table B", you're users will have to remember "table A has a one to many relationship with table B that can be accessed using another function name". It's more information that has to be remembered, and it's likely to be forgotten quickly.

Different users will understand different patterns. A usability engineer would tell you that you should understand your users. This means that you should understand what patterns your users can use easily and what you'll have to teach them. Your goal is to avoid teaching them.

Explorable Interfaces

Usability folks also like to create explorable interfaces. That is, they want to make it safe to try things out. My web browser does this by allowing me to hit the back button after I click on the wrong piece of underlined text. That's great for users since they get to explore the web without losing much time. Library authors can also try to do the same thing.

How can a library be safe to explore? There are a lot of different tricks that authors have used. A combination of multiple techniques is probably the best idea.

A good library for a compiled language will fail to compile when you try to use it incorrectly. It might even give you a clear error message when you do something wrong. An easy way to do this is to use type checking of function parameters. You can go a lot farther, though. For example, if one thing has to be done before another, then you could have the first thing return an object that has to be passed to the second thing. If the compiler helps a programmer figure out the library, they will be more willing to explore different parts of the library. To a usability engineer, the cost of trying something new is reduced.

Making it easy to write tests for your code can also make things easier to explore. Interpreted languages frequently use this as a substitute for the first technique, but it's useful for compiled languages as well.

Documentation is a great way to make a library easy to explore. If you can look up exactly what a function does, then it's a lot easier to use it correctly, and it becomes a lot easier to try new things out with the library.

Usability Testing?

I've never heard of anyone doing usability testing on their library, but it does happen accidentally. I frequently write libraries for use by programmers that I work with every day. If a library fulfills a real need, then those programmers will use it. They'll try to use it in ways that I didn't foresee, and I may have to modify my library to allow their new use. They might make some bugs that I didn't anticipate as well. In some cases, I can go back and change the API to make it more difficult to create those bugs.

This accidental usability testing is about as much as a typical library author might do. Could you do a real usability test? How might it work?

I can imagine telling a coworker to go through a simple use case for a new library. I could watch them try to figure out what's going on. Is it obvious that a mutex has to be held while you make a certain set of calls? Is the name of one of the functions unclear? Is the documentation incomplete somewhere? These are exactly the sorts of questions that usability testing should be able to uncover.

If a library had to be easy to use, this sounds like it would be the way to do it. I've never even heard of anyone trying it in an organized way. Is there a good reason for this, or are library designers just lazy?

This originally appeared on PC-Doctor's blog.

No comments: