The Usability of Programs, Part 2 of 2

October 22nd, 2007 | by Bill Kayser |

Here are some other principles of UI design that apply to program design:

Reduce Cognitive Load. This guideline in UI design is about minimizing the amount of things a user has to know in order to be able to use a tool effectively. Likewise, a programmer shouldn’t have to subclass five different classes just to effect one small change to an application. For instance, I often find that in order to add a new behavior interactive application I may have to learn the logging framework, the undo/redo mechanism, the localization framework, and the validation framework–on top of whatever complicated hierarchies exist in the model and views. Things usually reach this state when developers anticipating future needs and striving for reusability and generality in their frameworks end up sacrificing simplicity and, ultimately, usability.

DaVinci VmanBe consistent. The brake pedal on one model of car shouldn’t serve as the accelerator on another. That would be dangerous. It can also be dangerous to mix thread safe classes with classes that aren’t thread safe, or to have methods accept null String values in some places and throw exceptions in others. If you adopt an idiom in your public interfaces, like converting exceptions thrown by delegate APIs to local exceptions, or using immutable objects as enumerated types instead of ints, then try to stick with it. Consistency fosters a perception of predictability and stability.

…But not too consistent. Jakob Nielsen, a well known usability expert, suggested that you can take certain principles too far, and the principle of consistency is one of those. He felt that Mac interfaces went to excess in trying to maintain consistency, to the point of defying common sense. A famous example: since the operation of removing things from a desktop consisted of dragging them to the trash can, the operation for ejecting a floppy disk was to drag it from the desktop into the trash can, an operation guaranteed to unnerve a user the first time they try it. In software, programmers often step into the realm of over-engineering in an effort to enforce consistency. An action in a user interface may implement an Undoable interface, but that doesn’t mean all actions should be undoable. One might take pains to separate UI code from Domain objects, but if it means introducing intermediary classes and interfaces just to keep domain code from importing javax.swing packages then it may be better to diverge from consistency.

Avoid modality. In many applications users are confronted with modal dialogs which force them to take action before they can proceed in other parts of the application. While a modal dialog is showing, all other parts of the interface are disabled. On the surface this may seem helpful to the user but oftentimes it’s just a convenience for the programmer who doesn’t have the inclination to design the data model so that multiple activities can be conducted concurrently (i.e., changing the properties of an Employee in a dialog while simultaneously deleting that employee in the parent window).

The same thing applies in program design. Sometimes when one object collaborates with another it makes assumptions about the state of that object. Its operation is only guaranteed to be correct under those assumptions. For instance in some data access object there may be operations which result in updating a database object. But these operations might assume that a transaction has been started and fail in the worst possible way if that’s not the case. Users of this class must be aware these methods can only be called in a transaction and keep track of the state of the transaction. An alternative design might encapsulate individual operations in a full transaction, or offer more support keeping track of the transaction state.

Avoid this kind of modality in your classes. You can’t drop all preconditions but the fewer opportunities for failure, the more robust the application.

HandleUtilize Affordances. Affordances are properties of an object that suggest some action can be taken. A door knob “affords” opening a door. A rectangle on a screen may not afford action, but if it is raised and rounded, resembling a button, it affords being pushed. For programmers, affordances might be properties of an interface which make it’s usage more clear. In a class, abstract methods afford overriding. If a class requires several instance variables be initialized when the instance is created, then the programmer should afford that action by adding parameters to the constructor to populate those variables, rather than rely on the caller to invoke setters. Good abstractions and well factored class hierarchies can afford subclass extensions, where flat class structures with duplicate code and concrete classes may not.

Adopt Standards. What more is there to say? Standards in User Interface design result in uniformity across user interfaces, giving the user a sense of familiarity when using an application for the first time. In programming, coding standards provide exactly the same benefit.

Provide Feedback. Feedback in user interfaces usually means giving some indication that a user action has been detected and interpreted. If the action was accepted then give an indication to the user of success. If the action results in an error, make that error known to the user directly. This could probably be interpreted several ways in the context of programming, but the best one would probably be the principal of “Fail Fast.” This means detecting an erroneous use of a class or method early and communicating the actual offense, preferably in a runtime exception, as opposed to letting it go and waiting until the effects of the error cause secondary exceptions which may not reveal the actual API violation. An example of this would be not checking for null values in method parameters but passing the null values on to subsequent calls until a NullPointerException appears in a lower level method. I don’t think you want to check every pre-condition to an exception since it makes methods very noisy, but a lot of times there are conditions which are more likely to be violated. Play the odds and enforce those when you come across them.

You can really go on and on with this idea. The principles of usability apply to any system that interacts with a user, and that includes a programming model. The goal of a great programmer should be the same as the great product designers: empower and delight your users. Programmers should never forget that ultimately their users are not CPUs but other programmers.

2 Responses to “The Usability of Programs, Part 2 of 2”

  1. By Ramesh Soni on Oct 22, 2007

    Regarding “Avoid modality”, there is another instance when the user is closing a edit dialog without saving the change. In this case we usually ask user for saving the changes done by him. This is usually done by adding dirty ability to our object.
    I read an article (http://www.codinghorror.com/blog/archives/000075.html) by Jeff Atwood, which says that your application should not ask for this. It should automatically save and version your changes. What is the most appropriate way of doing this? Almost all of the projects I worked so far don’t have this feature.

  2. By Nidhee Pathak on Oct 25, 2007

    Assumptions on behavior of an entity which is external to the current scope of context is a dangerous thing. This holds good in mostly all cases whether it is the user interface design, integration with external systems or integration between different components.
    It is important to make sure that the component in question should be independant in its own right and even if it is required to work in conjuction with another, it should be completely usable (and re-usable!) on its own.

Post a Comment