Matt Gemmell

TOLL is available now!

An action-thriller novel — book 2 in the KESTREL series.

★★★★★ — Amazon

Engineer Thinking

development, interface & user experience 4 min read

I made a remark on Twitter the other day that gave rise to a discussion, and a few of the comments exemplified something I want to briefly talk about.

The actual topic of discussion isn’t particularly germane to my point, but suffice to say that it concerned a situation where Xcode (the development environment for Mac and iPhone/iPad programming) wasn’t doing anything to assist in a very common situation where you’d want to choose one of two possible courses of action, due to an underlying feature of the programming language used.

In probably more than 80% of cases, one particular choice would be made. My point, of course, is that Xcode ought to default to the most common choice, but transparently allow overriding that choice if the other option was needed.

Many people readily agreed, but there were two other types of response which stood out. They were:

  • Xcode can't know for certain which choice you want.
  • It's not Xcode's fault anyway, because it's due to an underlying feature of the programming language.

Both these responses illustrate what I call engineer thinking, and it’s something that’s both understandable but also incredibly damaging to the user experience of software. (A brief note is appropriate here to say that I’m a software engineer myself; I’m not just pointing fingers.)

Engineering in the real world has taught us (usually the hard way) about tolerances and precision. The axle must be of uniform strength, the furnace must run at a controlled temperature, the structural properties of supporting columns must be carefully designed. Reality tells us that being exacting, and producing the same outcome each time, is the key to not only reliability but even to feasibility itself. That’s all well and good, and has given us our civilisation.

But a problem arises when you allow precision-based design principles to hinder user experience. All too often, when faced with a decision about how to implement certain functionality, engineers take the extreme position that:

  1. A feature must be exactly what 100% of users want.
  2. If the above isn't true (and it almost never is), the feature must be configurable.

This binary approach is gravely wrong, and unjustly offloads decision-making onto the user of the software. We’ve all seen where this approach ends up: multi-row sets of tabs, scrolling panes of checkboxes, nested radio-buttons and a general overload of configuration.

It has become increasingly difficult to avoid choices in our daily lives, to an extent which many of us find intrusive and counterproductive. Buying coffee in a shop you’re not familiar with leads to momentary paralysis as you work out how to convey the fact that you just want a regular, black filter coffee. This isn’t the way forward.

From the user’s perspective, there is always a default. The engineer will then argue, correctly, that different users will have different opinions as to what that default should be, but here the Universe steps in and reminds us that there’s always a “usual way”. There is always one particular behaviour or configuration or setup which suits more people than any of the others (surprisingly often, there’s one which suits more people than all the rest put together). That is your default behaviour.

The existence of uncertainty is not an excuse for exposing it to the user.

It is software’s responsibility to mask uncertainty and to make the effort to provide a sensible default behaviour. Many users will care more about the fact that there is a default than what the default is. Choice means decisions, and decisions mean effort and second-guessing, and loss of focus and time. The best choice in software is a choice which has already been made for you, invisibly.

There are of course situations where choice is needed, as indeed in the case which spawned this discussion. The key realisation is that there are different ways to present choice. Too often, we’re given choice as a first resort; instead, present choice as a last resort. If the user must be able to choose, then let them do so by overriding a sensibly-chosen default behaviour - and ensure that such situations are as rare as you can make them.

Software cannot just wash its hands of issues of technical complexity or uncertainty; it’s not remotely OK to simply offload that work to the user. Software intended to help with a given task has an implicit expertise; we assume that our photo-editing software knows more about photo-editing than we do. Expertise carries a duty of care whereby the expert is expected to provide the benefits of expertise without the full cost of knowledge. That’s why experts are useful! The same holds for software.

The primary expression of expertise is in knowing effortlessly what the right course of action is in a given situation, and carrying it out without micro-management or endless justification. Make your software such an expert, and a guide and assistant to the user. Don’t force the user to make your software’s decisions for it, or to repeatedly bow down before its keen grasp of the vagaries of choice and uncertainty.

It all comes down to a question of art. Our art (that of software engineering) is not in making it work. If you see it as a significant success that you managed to name some methods, or write code that compiles and runs (or implemented a heap sort, or found the bounding box for a set of points, or parsed some XML), then your career goals are low indeed. Anyone in this industry can do that stuff, including any reasonably proficient final-year undergraduate in Computing Science. That’s core-skillset, vocational learning. You’re not aiming high enough.

Our art is in making the abilities of our software accessible to those who do not know how it works.

Your chance to demonstrate skill and professionalism and genius is by effectively hiding all the circuitry and wiring and batteries and screws behind one big shiny “Get the Job Done” button, whose apparent function is almost magical.

If you’ve exposed underling complexity or unnecessary choice in your software because you see those things as inevitable, it’s because your job isn’t finished. If you’re going to write GUI software for other people to use, do it properly, and treat those people like human beings instead of software engineers. If you want to expose complexity to the user and wash your hands of it, write command-line tools - or utilities that are used exclusively by other machine processes.

You can’t have it both ways. Writing GUI software is for people who strive for excellence not only in the “software” part but in the “GUI” part too.

If you enjoyed this article, you might be interested in following me on Twitter, enquiring about my iPad (and iPhone and Mac) development services, or listening to my thoughts on software design on The MDN Show podcast. I'll also quite shamelessly link you to my Amazon wishlist.