Designing for user flexibility, and allowing for the knowable and unknowable.
Humans are Messy
Designing a UI would be a lot easier if users came with a spec. If we had a documented listing of everything a user can output and how they respond to every input, user interface creation would be a simple if tedious endeavor. And if there were any problems with product after release, we could just lookup the spec, and say, “Ah, userâ€™s fault. Not performing to spec. Swap in another.”
But no, users are too complicated and variable to have a spec. Thus, we must also build in flexibility to cope with that complexity and variability. Humans will make two very different inputs (e.g., type “4/21/08″ and “21 April 2008″), which to them have the same meaning. One day, a user wants to print a document by first selecting the number of copies then the printer, and the next day the same user wants to select the printer first and then the number of copies. Users will vary their inputs but consider them semantically the same.
Providing this sort of flexibility is a key principle of good user interface design. As much as possible you want the user to be in control of the application. In general, that means the user interface should let the users do whatever they want, when they want, however they want. Itâ€™s part of adapting the machine to the users, in this case adapting to the usersâ€™ fundamental variability, rather than forcing the user to adapt to a machineâ€™s rigid requirements.
Reality is Messy
Thereâ€™s another kind of user interface flexibility which is really more about adapting the machine to the outside world, rather than adapting to the user. Often the user needs flexibility not because of personal habits or preferences, but in order to cope with an event that was not anticipated by the machine designers.
In many systems, the role of the user can be thought of as the interface between the machine and some vague world Out There. The machine receives input from the user, which the user received from some other source. The machine sends an output to the user, which the user takes to some other destination. The user thus acts as a translator, processing machine inputs and outputs to connect it to Out There.
With increasing automation and connectivity, the more mechanical aspects of the userâ€™s translations are being subsumed by the machine. Handheld devices replace paper forms, eliminating the need for a clerk to copy them into a terminal. Bar code and RFID readers track objects rather than humans reading labels and paperwork at checkpoints.
We can expect this to increase, but the userâ€™s role as intermediary to reality will remain. Machines are designed in accordance with a human-understandable abstraction of reality. Information systems, for example, slice and pigeon-hole the world into relational databases and stored procedures. However, like humans, reality is complicated and variable, and completely lacking a decent spec. Increasing automation and connectivity allows the machine to cope with more inputs and outputs on its own, but there will always be exceptions, and human users will be the best entity to handle these exceptions. They work at a level of abstraction above the machines, managing the automation.
This means that the user interfaces to our machines will increasingly need flexibility, to allow the user to handle exceptions the machine canâ€™t handle because the designer couldnâ€™t anticipate them. In its ultimate form, all user tasks will be about flexibility because humans are better at flexibility than machines, while machines excel at repetitive inflexible tasks.
Designing for flexibility first means finding out as much as feasible about the user variability and exceptions in the course of gathering requirements and researching users. As your users and subject matter experts describe the tasks and business processes, you should ask for each step in the process what can go wrong and what is done about it. What happens if a customer orders something that is no longer available? What happens if a customer never pays?
This inquiry is essential to design for flexibility, but you want to be careful how you treat the information you gather. You want to avoid designing a separate UI element for each exception. You donâ€™t want to pack the app with a load of individual “magic” features intended to handle every specific deviation. This adds excessive complexity, elevating the cost of the development, and making for a more confusing user interface for the users.
Worse, it may not even cover all the exceptions you ultimately have to handle. Our normal design procedures arenâ€™t really geared to developing flexible systems. Requirements gathering, contextual inquiry, usability testing, and hit log analysis tend to emphasize normal processing, rather than the exceptions. Even if you could observe everything the users do, you would at best know only the exceptions that have occurred, not necessarily all those that can occur. Even if you asked users and stakeholders every conceivable question, they can only tell you what is currently known, not necessarily all there is to know.
The result is that with each new version of the app, you end up adding addition UI elements to handle the exceptions discovered since the last version, and the app becomes increasingly bloated, and thus hard to use and maintain. You want to avoid the mentality of “got a problem, get a dialog box” in your designing. Research is necessary to create a properly flexible design, but ultimately flexibility comes more from following certain design tactics or approaches. There are three tactics to follow to make flexible designs:
- Least Restriction.
It sounds obvious, but a UI will have the most flexibility if it is designed to have the least restrictions on user behavior. A flexible UI doesnâ€™t box the user in. For each limit you must place on the user, select the specific criteria that prevent the anticipated problems while allowing the greatest latitude of user action.
Take, for example, date validation. The problem is not to make the user use a proper date format. The system can autocorrect any weird format the user uses and echo it back to the user for implicit verification. The problem is to convert the user input into some kind of machine-interpretable date. So, ask yourself, what is the very minimum a machine needs to get a date?
Well, letâ€™s say your user research shows some users use a slash to delimit the components of a date (as in 4/29/2008) while others use dashes (4-29-2008). So, of course, you should allow for both, but donâ€™t stop there. To draw out a date you can treat any special character as a delimiter. The following would all be interpreted as the same date:
- 4 29 2008
Why? Well, why not? Designing for flexibility is more than accommodating the requirements and findings from your user research, because that is going to make a UI that allows only anticipated user variation. To allow for unanticipated variation, treat the variability in your research not as targets to hit, but as points on a surface you have to cover. In the above example, youâ€™ve noticed, not that users use “-” or “/” to delimit dates, but that they use special characters to delimit dates. Thatâ€™s the least restrictive interpretation of the research.
Other field requirements should likewise be given a skeptical appraisal. There is no excuse for a modern app or web site to require the user to omit spaces from a credit card number or enter a phone number with “properly” placed parentheses and/or dashes. The Massachusetts Registry of Motor Vehicles site requires users to enter the registration fee amount with the cents, even though itâ€™s always (for me anyway) a round dollar amount. And donâ€™t you dare include a dollar sign.
Oh, for Peteâ€™s sake! Buy a programming book, people!
Recommend, Do not Require
You should also appraise proposed required fields: is it really necessary for the user to give a name or phone number? By “necessary,” I mean the system cannot work without it, not that the Sales department really really wants names and phone numbers.
In general, you should resist using the system to enforce good practices or business policy, because some day, users are going to have an exception that requires them to go against business policy for the good of the business. Requiring that a resource scheduling window accept only dates in the future sounds like a perfectly reasonable limit, perhaps preventing human errors (like forgetting to increment the year in January). Then one day the system is down for a week, and users have to enter the schedules retroactively, otherwise the resources canâ€™t be charged to the right departments.
Iâ€™m not saying you shouldnâ€™t design the system to minimize human error. Iâ€™m only saying be careful about forbidding alleged errors. In the case of the date example above, provide a sanity check rather than validation. Warn the users when they schedule something for the past, but donâ€™t forbid it. Sometimes the UI can be designed to make such errors apparent without using message boxes. Read-only text fields in general should be selectable and copyable just because there is no good reason not to. You may not be able to imagine are reason to copy certain text, but it isn’t an error to try. Don’t prohibit it.
Support Freer-form Input
The very idea that users need to chop up their input into little discrete fields should be viewed with skepticism. Many web apps require users to enter addresses with separate controls for house number and street, town, state, and zip code. If you’re thoughtful, you might include a “Street 2″ field. Some apps have a separate field for area code from the rest of the phone number, or break a date down into separate fields for day, month, and year, or, even more silly, separate fields for a time’s hours, minutes, seconds, plus a dropdown for “AM” or “PM.”
Each of these attributes can be single text box. Mapping apps demonstrate we have the technology to very effectively pull out city, state, and zip from a free-form multi-line Address text box, assuming that level of breakdown is actually needed for the database. With dates, there’s ambiguity in distinguishing months from days when only numbers are entered, but if you auto-correct the input to use the name of the month, the user can verify the app’s interpretation.
Partly, using a single field for things like address and phone number is a matter of user efficiency: Users can enter familiar strings into a single text box faster than into multiple text boxes, which require additional planning and navigation. But it’s also a matter of flexibility. By providing a single multi-line text box for address, users can have as many lines as they’re used to. A single box for addresses or phone numbers eliminates the problem of accepting international formats. A single box for date and/or time opens the possibility of supporting micro-grammars, where the user can validly enter things like “2 tomorrow.”
Comment fields provide a high level of flexibility that conveniently handle many exceptions, and you should generally include comments fields at key places in the UI. Often the problem with an exception isnâ€™t so much that the user is going against policy or practices as thereâ€™s no way to document why itâ€™s necessary to go against policies and practices. Providing comment fields provides remarkable flexibility for handling exceptions that no one imagined were possible when the UI was designed. Comment fields are something you should include as a matter of course, even when there is no specific use case that requires them.
As Much As They Need
The Least Restriction tactic means avoiding arbitrary limits of quantities in interaction. Just imagine a little kitten dies every time you use a fixed-sized array for any user interface element or collection of data objects. Prior to 2007, Microsoft Excel allowed only 3 conditional format rules. Both MS Word and Excel allowed only 3 levels of sort. Why? Sure, maybe user testing suggested users never needed more than three, but user testing covers only the scenarios you know of. The proper least restrictive interpretation for these situations is, “Users need to sort/format on multiple levels/criteria.” How many? “A lot.”
Looking at the Sort dialog box above, you may argue that they had to limit the number of levels to keep the dialog from becoming too complex. However, if we look at the Conditional Format dialog, we see that it is possible with clever design to have a UI that in principle supports an arbitrary number of criteria.
This is a superior design, not only because it supports greater flexibility, but also because it is naturally simplest for the simplest case: If the user has a single criterion, the user sees only a few controls.
The Least Restriction tactic includes allowing for the full range and capability of modern graphical user interfaces. For example, you should allow multiple windows of the same type, which may or may not be showing the same data objects. Windows should be resizable and movable, with scrollbars appearing as necessary. These capabilities should be treated as standards. You donâ€™t need a usability test or use case to justify them. On the contrary, they should only not be done if thereâ€™s a compelling and substantiated usability reason to do so.
Flexibility is also maximized if the user has the ability to execute each action and processing step individually and independently. This gives the user the ability to mix and match commands to modify the usual process should the need arrive.
Say No to Modes
That means, first and foremost, avoid modes. Ideally, you want everything to work irrespective of the context. In particular, avoid modal dialog boxes, especially complex multi-purpose ones. Preference or Options dialogs, for example, should be modeless, allowing the user to move around on the underlying primary window to see the effects of one option setting over another.
Wizards, similarly, are antithetical to flexibility. For example the typical e-commerce site puts the shipping cost calculation somewhere on Page 17 of a lengthy checkout wizard. That may be fine for the usual use case, but what if the user wants to know the shipping cost without entering a lot of irrelevant information? Applying incrementalization, you allow the option to calculate shipping any time: the user can enter the zip code of the destination, and the shopping cart keeps a running total of the shipping costs for the various shipping options for the remainder of the session.
The incrementalization tactic is one reason that object centered UI structures are generally more flexible than task-centered UI structures. In task-centered structures, the UI presents a path through the task one modal step at a time. Unless the designer thought to include additional paths (which adds complexity), the user is stuck on the one path. In object-centered structures, all actions are made available for the currently displayed data objects.
That Means You Hidden Modes Too
Modes donâ€™t have to be explicit, like a wizard or dialog box, to interfere with flexibility. Many web apps fail to preserve user input. If the user fills a form then leaves it for another page (perhaps to refer to something in order to complete the form), often a web app will clear the form. Essentially, this locks the users into a mode: they must complete and submit the form before doing anything else. Anything they needed to do to use the form they needed to get done before they started filling it out.
In contrast, incrementalization means avoiding conditions where the users’ earlier decisions commit them to a single course of action. To incrementalize such a course of action, push off all user commitments to the last possible moment. For example, in games or web browsing, the app shouldn’t ask a user if they want to save a current session on exiting. Maybe the user will only know if she or he wants to restore the session sometime later. Therefore, instead, the app should save the session no matter what, and provide and option to restore it the next time the app is started.
In some cases you want a series of steps to be executed automatically to save the user work. For example, your enterprise app may each month automatically aggregate financial data, generate a pdf report, and email it to a list of users. For flexibility purposes, however, a UI should be built in parallel to the automation that incrementalizes the process. Users can independently aggregate the data, generate a pdf report (from any selected aggregates or even any set of data objects), and email (any selected pdf to any selected users). Parameters for each step by default should be set to what the automation used, but users can then change them for a specific run. Incrementalizing the process allows users to intervene at any step and modify the process, overriding the automation to handle exceptions.
In keeping with pushing off user commitments, automated processes should be incrementalized both forward and backwards. Users may not have realized an exception has occurred until after the automation has run. Thus, whatever the process has done, the user should be able to reverse it one step at a time. This is not necessarily through an Undo feature, but may be through dedicated override controls and data objects for the automation. Email that was been sent out can be yanked back (if unopened). The pdf that was generated can be pulled up and modified and re-sent, maybe using a modified user list. Aggregated data that went into the pdf can be adjusted, and the remainder of the process re-executed.
More Flexibility with Less Complexity
Incrementalizing a process often provides flexibility while controlling complexity. For example, consider making a Find and Replace feature for a table layout. Your first instinct may be to use the sort of dialog found in office suites, with one text box for what to find and what to replace.
But that’s not very flexible. The user can’t specify the particular field to search. Furthermore the dialog can only replace the found text with the replacement text. Often for a table layout, the user will want to select certain data objects based on the values of one attribute, and change their values of a different attribute, essentially performing an Update query.
Okay, so the dialog needs controls to specify the searched attribute, and more controls to specify the attribute to get new values, and, hmm, you know there might be more than one for each. Pretty quickly this task is getting too complex for a single dialog.
However, if we incrementalize the process, we see there are two basic steps:
- Select data objects based on attribute values.
- Modify selected data objects attribute values to new values.
What if we made each step separate and independent? You’d have a modeless Find dialog that would look something like this:
And a modeless “Modify” dialog box like this:
Well, they’re still pretty complex dialogs, but not as bad as combining the two into one dialog. There’s full flexibility: the user can select data objects on any attribute values, and independently modify any values, either all at once, or one data object at time. Incrementalizing Modify into its own dialog provides additional flexibility you can’t get in a combined Find and Replace dialog: it can be used without Find at all. The user can manually select multiple data objects and modify the attributes of all of them together. The user can Select All data objects and update the entire table all at once. By a complexity-to-flexibility ratio, incrementalization is a winner.
In some cases, you may want to provide a interface with the ultimate in incrementalization: a command language. If a subset of users will have or get the necessary expertise, you may want to provide a scripting or macro capability, or accept SQL commands. Short of an actual command language, you may want certain input to be interpreted with conventions found in command languages. For example, your Search box may accept wild cards, regular expressions, and Boolean logic. As another example, you could provide the users with a capacity to add custom attributes to data objects where the attribute value is an arithmetic or computational function of other attributes.
The Commonality tactic collects similar actions under the same user interface. Where Incrementalization seeks to break down the UI into many simple independent tools used in combination for tasks, commonality seeks to consolidate those tools into a smaller set of multi-purpose tools. Employing Commonality is your chief means of controlling complexity in a flexible UI.
Combine and Expand Commands
To use the Commonality tactic, review all your features and look for similarities. For similar features, design a single general UI that accomplishes both. For example, suppose for some mapping software you have requirements to allow the user to change the symbols for waypoints and the user’s current position. In using the Commonality tactic, the UI should be the same. For example, rather than one Change Ownship Symbol menu item and one Select Waypoint Icon menu item, you have a single Change Symbol menu item that opens a dialog for the current selection. The default and maybe available symbols may be different for waypoints and ownship, but the UI is the same.
As with using the Least Restriction tactic, to get real flexibility out of this, you should treat the requirements or user research results not as targets to hit but as representing a surface to cover. You know that users need to change waypoint and ownship symbols. Perhaps you should use the same UI to allow changes to other symbols too. Routes and tracks, for example should also employ the same UI to allow the user to specific the color and style of route and track lines. It wasn’t in the requirements, but someday it’s going to be very handy when a user is trying to compare multiple tracks, and can thus color-code each of them.
Abstracting Objects and Actions
The Commonality tactic avoids the “got a problem, get a dialog/page” mentality. Today, for example, sophisticated e-commerce sites have shopping carts, wish lists, registries, and recommendations. They are all simply user-created lists of products. The UI would be simpler and more flexible if there were just Lists created through a common UI. Apply the Incrementalization tactic and the way a list is used becomes independent from the process of creating a list. Once the user creates a list through a common UI, the user can then decide to:
- Purchase the products for one’s self
- Purchase the products for someone else
- Save it for later consideration
- Publish it as community recommendations
- Provide access to use as a registry
- Distribute it by email to a friend
- Select and edit items (e.g., to make returns or exchanges)
- Aggregate and download multiple lists (e.g., for budgeting purposes)
- Any combination of the above in any order
Using the tactic of Least Restriction, the user can have multiple lists active at once. Now while shopping for gifts for someone, the users can select for themselves something they happen to see and like.
Leveraging Existing Knowledge
Commonality leverages user knowledge of existing features to help them learn new features, making for a more fluid-feeling interface. The UI not only is flexible, but it feels flexible. For example, compare how MS Word and Excel handle copying formats to different text or cells. In Word, we have the Format Painter, a pointer-tool that, when selected, can be dragged across any text resulting in the text assuming the format of the last cursor position. Many users like it, but I find it awkward and inflexible, partly because it’s unlike other parts of the UI and partly because of poor incrementalization.
- Once the tool is selected, the user cannot do anything else other than copy a format, thus constituting a mode.
- If users want to format multiple selections, they have to remember to double click the tool so it stays on for more that one selection, thus user commitment comes early.
- It turns off if the users move text or undo anything (including undoing formatting one character too many), making it even more modey.
Compare that to Excel, where it was recognized that copying a format has a lot in common with copying in general, so this feature is accomplished through Paste Special. This makes it easier to find and easier to learn. Because it relies on conventional selection, the users have more familiarity and flexibility in selecting the cells to be formatted. In addition to dragging to select, users can select discontiguous cells with control-select and they can select with cursor keys, neither of which can be done with Format Painter. With Paste Special, incrementalization is better with later user commitment:
- Users can decide what to paste (format, values, formulas, or whatever) after they arrive at the cells to be modified.
- Users can perform almost any other task between selecting the cells to copy and effecting the copying -moving cells, entering formulas or values, sorting, whatever.
- Undo only undoes what the user just did, allowing the users to re-apply the format copy if they screw it up.
Commonality is the other reason that object-centered UI structures tend to be more flexible. Commands can be overloaded so that the exact action can be adjusted for the current selection. Copy and Paste menu items, for example, can be applied to text, shapes, records, and files all in the same application. If you’re designing an object-centered UI, you can use the Commonality tactic by asking yourself:
- For each object, how many commands can be made relevant?
- For each command, how can we make it act on a given selection?
- How should it act given the object class of the selection?
- How should it act given multiple selected objects?
Object-centered UIs lend themselves very well to having the following general-purpose tools that ideally can be applied to any object class in the app:
- Visualize a data object (e.g., select attributes to show or how they are shown)
- Get details on an object (e.g., by linking or “drilldown”)
- Update an object’s attributes
- Create and associate objects
- Delete or remove (dissociate) objects
- Re-associate objects (i.e., “move”)
- Copy an object
- Convert an object to another object class (often overloaded with “copying”)
By supporting full-featured multi-selection conventions, each of the above can be done on multiple objects at once.
For collections of objects, one can also:
- Filter (sometimes can be overloaded with Search)
- Aggregate (e.g., display sums and averages)
Key to this is making sure any command or selected object can work across any context. There’s little point in supporting copying text from one part of the app to the other if it’s going to copy it in an incompatible format.
Leveraging Outside User Resources
The Commonality tactic includes providing a means to submit an object to a given action not only within the app but outside of it. Flexibility is greatly enhanced if users can exploit resources beyond the ones you thought to provide in your app. Typically, all that should be necessary is for the user to select the object, and the app will make the necessary conversions for it to work outside (e.g., when copying and pasting between apps using the clipboard). Sometimes, the conversion needs to be explicit, and thus you should provide Import, Export and Print features. Ultimately, this simplifies your job as now it becomes unnecessary to implement features that are better handled by other apps. Don’t bother making a graphing feature for your database app when you can export the data to Excel, especially if your users already know how to graph in Excel. You don’t need to make your report generator into a desktop publishing app. Marketing already has publishing apps. Export to them.
Flexibility versus Other Usability Goals
Flexibility is one desirable characteristic of an application, but there are others, such as user efficiency and learnability. As we have seen, sometimes designing for flexibility makes for a more efficient and learnable app. The Least Restriction tactic allows users to do things the way they are used to doing. The Incrementalization tactic breaks tasks down into simple pieces the user can handle one at a time without stopping to plan ahead. The Commonality tactic allows users to apply their knowledge of one feature to another. By learning how to do things normally, users are also learning the tools to handle exceptions.
However, there are times when flexibility is a trade off with other UI characteristics. Commonality may mean that users have less to learn, but it often means abstraction of features, which, while simplifying, may make things unfamiliar to user. For e-commerce sites, for example, users generally understand the concept of a shopping cart and how to use it. Eliminating it in favor of general-purpose lists, and users may not figure out how to buy things. Not a good trade-off if you want to stay in business. Adding controls to override automation or allowing pasting of just formats can clutter windows, making simple execution of automation or pasting slower and harder to figure out. Object-centered UIs are more flexible in general but take longer to learn than Task-centered UIs, since the latter lead the user by the hand through the task.
Therefore, when designing for flexibility, you should consider the context of use and whether flexibility, especially for unanticipated exceptions, is worth the price in other dimensions of usability. An airport self-check-in kiosk wouldn’t benefit much from allowing a lot of flexibility because users don’t have time to learn a relatively complex UI to capitalize on it. The overriding goal of such a design is to move the untrained user through the normal flow as quickly as possible. It’s better to have attendants on hand to handle exceptions through their own apps.
Fortunately, flexibility is a characteristic most likely to be needed by expert users under rare circumstances. By definition, exceptions are exceptional. Thus the usual techniques of proportionality and progressive disclosure, can be used to make flexibility available while insulating the normal work process.
Flexibility versus $
Finally, there is the development cost of building flexibility. Some application of the tactics of flexibility will save development costs and time in the long run because they create a foundation in the UI for additional features and last-minute requirements. When an influential client insists on Just One More Thing, it’s great to be able to say, “you can support that by using the comment field.”
Nonetheless, some efforts to increase flexibility, such as adding overrides to automation, increase development time, and a certain level of judgment is necessary to know what to include or not. The more complex the application, the more users it will have, and the longer it will be in use, the more you can justify the cost of building in flexibility. Is it really worth the cost of creating and testing additional code to allow a user to enter “today” as a valid date? Do you really need to make that CSV export function, when there is no record of that ever being useful and all your subject matter experts insist, “we would never need that.”?
Until they do.
Problem: Designing for flexibility, including needs and uses that cannot be anticipated.
- Create Least Restrictive design solutions.
- Allow any format of input that can be interpreted.
- When feasible, solicit free-form text input and parse it automatically.
- Require only input absolutely necessary for computational functioning.
- Advise against actions that may be errors or poor practices, but do not prohibit them.
- Avoid arbitrary limits on the number of things a user can work with.
- Support the usual GUI window capabilities.
- Supply comment fields for users to document exceptions.
- Incrementalize features into separate independent actions that can be combined in any order.
- Avoid explicit modes and wizards.
- Preserve input when users navigate away from a window or page.
- Push off user commitment to execute a process until as late as possible.
- Provide forward and backward overrides for each step of automated processes.
- Breakup complex actions into independent UIs.
- Consider a macro or scripting capability, and other user customizations.
- Develop interfaces so multiple processes can use common UIs or resources.
- Abstract data objects so the same class has multiple purposes.
- Overload commands, so a single command has analogous effects on multiple classes of objects.
- Leverage existing user knowledge, such as how to multi-select, and resources, such as outside apps.
- Support basic functions, such as move and copy, for all data objects.
- Favor object-centered user interface structures.