Don’t design like a programmer

I sometimes say that UI looks like it was “designed by a programmer.” This isn’t some arbitrary remark—rather this is my cute way of describing a class of UI design mistakes that programmers are particularly prone to make. Contrary to claims made by Alan Cooper, I don’t think this style of UI is the result of some programmer conspiracy to inflict their ill will over hapless users. Rather, these designs happen because programmers find them easier to develop, don’t notice their usability problems, and often aren’t aware that there are better solutions.

New! By popular demand, I have posts that show what a good design looks like and how to get it. Please check Don’t design like a programmer, part 2 for a design process and Don’t design like a programmer, part 3 for the new design.

These designs usually stem from directly mapping a data structure into a UI and expecting the result to be usable. To see what I mean, let’s assume that we have a data structure like this:

struct UserOptions {

bool Option1;

bool Option2;

String Option3:

String Option4:

...

};

It’s natural to assume that a good UI might look something like this:

Now all you have to do is present this UI to the user, have the user provide all the information, and continue. Pretty straightforward, right?

While sometimes this approach works just fine, all too often it leads to a poor experience. Here are some of the reasons:

Data structure issues

Using variable or technology names as control labels The variable names work fine for the code, so why not use the same or similar names in the UI? The problem is that these names, often based on technology, may not be all that meaningful to users. Devices properties and settings are full of examples. For example, how many users know that “duplex printing” means print on both sides of the paper?

Warning sign: Control labels based on technology rather than purpose.

The variable names work fine for the code, so why not use the same or similar names in the UI? The problem is that these names, often based on technology, may not be all that meaningful to users. Devices properties and settings are full of examples. For example, how many users know that “duplex printing” means print on both sides of the paper? Control labels based on technology rather than purpose. Letting variable types determine control types The common data types of strings, integers, and Booleans readily map into text boxes, radio buttons, and check boxes. The problem is text boxes, being the most unconstrained control, require the most knowledge and effort for users. Mapping to richer, more constrained controls takes more effort for programmers.

Warning sign: Overuse of text boxes and check boxes.

The common data types of strings, integers, and Booleans readily map into text boxes, radio buttons, and check boxes. The problem is text boxes, being the most unconstrained control, require the most knowledge and effort for users. Mapping to richer, more constrained controls takes more effort for programmers. Overuse of text boxes and check boxes. Exposing raw, unformatted data It’s much easier to expose raw data than to translate it into a format that is more meaningful or natural to users. For example, it’s easier to expose a raw date than a properly formatted date for the user’s locale. It’s easier to display a plain date than the useful, relevant information behind the date (such as days until deadline, age when an event occurred, etc.) Likewise, raw data like “1KNG 1BDRM EVO STE NSM” is easier to display than the more comprehensible “Evolution Suite with 1 King Bed (non-smoking).”

It’s much easier to expose raw data than to translate it into a format that is more meaningful or natural to users. For example, it’s easier to expose a raw date than a properly formatted date for the user’s locale. It’s easier to display a plain date than the useful, relevant information behind the date (such as days until deadline, age when an event occurred, etc.) Likewise, raw data like “1KNG 1BDRM EVO STE NSM” is easier to display than the more comprehensible “Evolution Suite with 1 King Bed (non-smoking).” Warning sign: Controls display raw, unformatted data that requires users to translate.

Controls display raw, unformatted data that requires users to translate. Exposing representation invariants In object-oriented programming, a representation invariant is a set of constraints that a concrete data type must uphold to correctly represent an abstract data type. Simply mapping a data structure to a UI would expose the invariant and put the burden of enforcing the invariant on users instead of the code. A typical example is having to enter a phone or part number in a specific format instead of the program handling any reasonable input.

Warning sign: Users required to enter data using a specific format.

In object-oriented programming, a representation invariant is a set of constraints that a concrete data type must uphold to correctly represent an abstract data type. Simply mapping a data structure to a UI would expose the invariant and put the burden of enforcing the invariant on users instead of the code. A typical example is having to enter a phone or part number in a specific format instead of the program handling any reasonable input. Users required to enter data using a specific format. Exposing special values A common programming practice is to assign special meanings to a special value, so, for example, a value of -1 might mean “not available” or “unassigned”. Simply mapping a data structure to a UI exposes these special values (typically through the control label), requiring users to know and enter them.

Warning sign: Control labels that explain special values.

A common programming practice is to assign special meanings to a special value, so, for example, a value of -1 might mean “not available” or “unassigned”. Simply mapping a data structure to a UI exposes these special values (typically through the control label), requiring users to know and enter them. Control labels that explain special values. Overusing error messages A related problem is display error messages for the slightest input problem, regardless of how clear the user’s intent or easy the problem is to correct.

Warning sign: Use of error messages for easy-to-correct input problems.

Simplicity issues

Not optimizing for the probable While from the code’s point of view any input is possible, from the user’s point of view not all input is equally likely. For example, while users could select any font, most likely users are going to select the last font, a recently chosen font, or a font chosen in the past.

Warning sign: Not optimizing for the most likely input.

While from the code’s point of view any input is possible, from the user’s point of view not all input is equally likely. For example, while users could select any font, most likely users are going to select the last font, a recently chosen font, or a font chosen in the past. Not optimizing for the most likely input. Over generalizing (the 0, 1, n problem) Programmers handle the absence or presence of something with a simple if statement, but handling 2 or more things requires a for loop. Exposing this generalization often leads to unnecessary complexity. From the programmer’s point of view, if you are going to design code to support a family, you might as well support a commune too. From the UX perspective, it’s far better to optimize for the common cases.

Warning sign: Not optimizing for the most common number of objects.

Programmers handle the absence or presence of something with a simple if statement, but handling 2 or more things requires a for loop. Exposing this generalization often leads to unnecessary complexity. From the programmer’s point of view, if you are going to design code to support a family, you might as well support a commune too. From the UX perspective, it’s far better to optimize for the common cases. Not optimizing for the most common number of objects. Asking for what the code needs vs. what the user knows What the code needs and what the user knows might not be the same. For example, the program might want an airport code, but the user might know the city. Or the program might want the telephone exchange code, but the user might not know what that is (it’s the three digits after the area code). While it’s easier to present what the program needs directly, it’s better to ask for input that users can provide easily and confidently.

Warning sign: Users have to look up information or need to use help to provide input.

Life cycle issues

Having baffling initialization Have you ever seen a large form where everything was initially blank and you had no clue what to do to get started? While zeroing out everything is a fine way to initialize a data structure, sometimes users need more than a blank form to get going.

Warning sign: Initial UI state is blank and difficult to figure out.

Have you ever seen a large form where everything was initially blank and you had no clue what to do to get started? While zeroing out everything is a fine way to initialize a data structure, sometimes users need more than a blank form to get going. Initial UI state is blank and difficult to figure out. Going all in Data structures reflect data types and hierarchies, but they reflect little else—they don’t reflect dependencies between members, or important vs. unimportant or required vs. optional values. Mapping a data structure directly to a UI would present all the data at once, without showing dependencies or optional values, or using progressive disclosure to hide infrequently used settings.

Warning sign: All input is always displayed and always required, even if unimportant, optional, or dependent on other settings.

Data structures reflect data types and hierarchies, but they reflect little else—they don’t reflect dependencies between members, or important vs. unimportant or required vs. optional values. Mapping a data structure directly to a UI would present all the data at once, without showing dependencies or optional values, or using progressive disclosure to hide infrequently used settings. All input is always displayed and always required, even if unimportant, optional, or dependent on other settings. Having all or nothing Similarly, while all elements might belong together in a data structure, they don’t necessarily have to be provided by the user all at the same time. Mapping a data structure directly to a UI would require the user to provide all the information before proceeding, whereas a better experience would be to let the user proceed with the task with only the minimum amount of information, and gathering the remainder only when needed.

Warning sign: Input is requested well before it is necessary.

Efficiency issues

Having a privacy hurdle If the data structure needs personal information or information that is difficult to obtain (such as having an account, finding an account name or password), users might be unwilling to provide such information—especially if such information shouldn’t be required to perform (or at least initiate) the task.

Warning sign: Users are required to have accounts, log on, or provide personal information unnecessarily.

If the data structure needs personal information or information that is difficult to obtain (such as having an account, finding an account name or password), users might be unwilling to provide such information—especially if such information shouldn’t be required to perform (or at least initiate) the task. Users are required to have accounts, log on, or provide personal information unnecessarily. Avoiding excise Even if all the other factors work out, the UI could be annoying if displayed every time a frequent action is performed. Frequent actions should be designed to reduce or eliminate any hurdles, typically by assuming reasonable default values.

Warning sign: Frequently performed tasks present an unnecessary dialog box instead of assuming defaults.

Even if all the other factors work out, the UI could be annoying if displayed every time a frequent action is performed. Frequent actions should be designed to reduce or eliminate any hurdles, typically by assuming reasonable default values. Frequently performed tasks present an unnecessary dialog box instead of assuming defaults. Handling scale Mapping a data structure directly to a UI might work well for a few variables, but the resulting UI can be a nightmare for dozens.

Warning sign: Way too many controls displayed on a single screen.

Mapping a data structure directly to a UI might work well for a few variables, but the resulting UI can be a nightmare for dozens. Way too many controls displayed on a single screen. Handling unexpected input Just because you don’t expect input in a certain format or find that format inconvenient doesn’t mean it’s wrong. If the user believes the input is valid, it almost certainly is. Check We cannot accept that behavior for an unpleasant but all-too-common example.

Warning sign: Unnecessary restrictions on input formats.

If you do only one thing: Think about UI as a means for users to achieve their goals and perform their tasks, not as a means to fill in data structures or make code happy. Poorly designed UI requires users to translate their goals into what the UI needs, whereas well designed UI does this translation for them. What at first appears to be easy and obvious UI design may prove to be a poor experience from the user’s point of view.

A challenge

How many of the above problems can you spot below?

Yup—this looks like it was designed by a programmer. For starters, notice how nearly all the controls are text boxes and check boxes because they map directly to the underlying data structure. While this UI has problems outside of those mentioned in this post (such as poor communication, task flow, and layout), fixing the core problems first will make other problems easier to solve.

Want to see how to do it right? Check out Don’t design like a programmer, part 3.

A bonus challenge

The User Options example has 6 minor guideline compliance problems. Can you find them?

Want to learn more? Check out UX Design Essentials and UX Design Basics

If you would like to learn how design UIs the right way, please consider taking my UX Design Essentials course or my online UX Design Basics course. I’ve designed both of these courses to help non-designers get started in UX design. I’ve only scratched the surface here.