If you consider a developer as a user, reading a book about usability engineering is mind-blowing, related to your code.
— Tobias Zander (@airbone42) 14. Februar 2015
This Tweet in 2015 blew my mind. I learned a bit about designing interactive systems and psychology in design, so I could relate immediately. It inspired me to a talk “Usability for Programmers” at WebCon Aachen, that unfortunately never went public because the event was cancelled, and I am yet waiting for a new chance to deliver it.
But I find the content too interesting to leave it hidden any longer, so here’s a blog post!
First, a few basics on usability that every software developer should know:
UX is not just frontend
The user experience of your application depends not only on (optical) interface design, there are many factors that come into play. For example:
Useful error messages
A useful error message has the following characteristics: explicit, human-readable, polite, precise and constructive.
Read more: Error Message Guidelines
If it is not possible for your application to respond immediately to a command, be aware of human attention spans and show feedback accordingly. 1
- 0.1 second is about the limit for having the user feel that the system is reacting instantaneously, meaning that no special feedback is necessary except to display the result.
- 1.0 second is about the limit for the user’s flow of thought to stay uninterrupted, even though the user will notice the delay. Normally, no special feedback is necessary during delays of more than 0.1 but less than 1.0 second, but the user does lose the feeling of operating directly on the data.
- 10 seconds is about the limit for keeping the user’s attention focused on the dialogue. For longer delays, users will want to perform other tasks while waiting for the computer to finish, so they should be given feedback indicating when the computer expects to be done. Feedback during the delay is especially important if the response time is likely to be highly variable, since users will then not know what to expect.
Read more: Response Times: The 3 Important Limits
Also known as “creeping featuritis”, this is the phenomen of more and more features added to a software, needed or not. As it is “creeping”, it is hard to notice, but you should strive to avoid it.
Programmers have big egos. Customers don’t always know what they want. Programmers often miss the distinction between what’s needed and what’s “neat”.
Read more: WikiWikiWeb: Creeping Featuritis
Think about how people will use your software and make common tasks easy. Also provide shortcuts for experienced users. And take into account that people make mistakes. An undo buton can save lifes!
Image source: tech4google.blogspot.com
Principles of interactive design
I already mentioned response times and error messages. But also don’t forget to give feedback when an action was successful!
Affordances are characteristics of an interface that suggest a certain action. For example, the shapes of door handles are designed in a way that we use the right action intuitively. A flat door handle suggests pushing, handle bars suggest pulling, a knob suggests turning.
But affordances are not only prevalent in physical product design. A pet peeve of mine are screen elements that are designed in a way of physical controls, but use the wrong metaphor.
Image source: https://commons.wikimedia.org/wiki/File:Scool_023.jpg
Take these switches: The physical switch suggests sliding it up and down. The equivalent on a phone suggests swiping it left and right. We recognize the shape and mentally map the concept. This works great on a touch screen, but it often gets carelessly copied for desktop devices, where you have to click on the switch. I once watched my mother in front of such an interface and guess what, she tried to drag the control with the mouse.
You want me to click on something? Make it look like a button, not a switch!
Image source: https://dribbble.com/shots/757243-Toggle-Buttons
Constraints are diametral to affordances. Design the interface in a way that undesired actions are discouraged (or rather: impossible).
For example, do not show controls that are not possible to use at the moment, or disable them to make it obvious what choices a user has at any time. With good constraints, you need less error messages. A user not experienced with your system will find their way around it with less trial and error and less frustration.
Miller’s Magic Number
The capacity of our working memory is assumed to be about 7 chunks of information (+/- 2), even for people with extraordinary memory skills. They mostly use it differently, with associations in the long term memory to make the chunks bigger. This is not excact science (see Is The magical number 7 still valid?), but it is that order of magnitude.
For example, a 5 digit number “52078” could be 5 chunks if I think of each digit separately, 3 chunks if I think of “52”, “0” and “78”, or 1 chunk, if I recognize that it’s my postal code, which I can recall from long-term memory.
Keeping this number in mind is important for things like 2FA codes, or even number of elements in a form.
Now for something completely different, and the actual topic of this post: let us think about our code as user interface and other developers as users. Oh, and if you are a one-man-show, consider yourself in 6 months as another developer.
Constraints and affordances in code
Let’s start with something obvious: Typed variables are constraints. In PHP with its loose type system, we have the choice to apply these constraints, with type hints and strict mode and thus, force our code to be used in the way we intended it to.
Then, interfaces in code are a kind of affordance. Your interfaces suggest a way how they are implemented, not only by their signatures which are enforced, but also by their names.
In classes, choose method visibility with caution and be aware what usage they suggest:
- protected methods afford overriding
- private methods constrain from overriding
So if you write a protected method, it becomes part of your API and you should not be surprised if people override it. Now you have to be careful not to break it.
For the same reason, if a class is not designed to be extended, consider making it
final. Read more: When to declare classes final
I already mentioned names. The importance of names cannot be underestimated. This holds true for any code, because you want to understand it when you read it, but even more for a public API, where the names afford certain usage (or not).
Miller’s Magic Number
To take the readers short term memory into account, the complexity of any unit of code should be as small as possible.
In practical terms, the following measurements should never be more than five to seven (ideally much less):
- Cyclomatic complexity
- Depth of the inheritance hierarchy
- Number of parameters
- Numer of attributes
I found another article that connects Miller’s Magic Number to programming and it explains it better than I could: The Magic Number Seven And The Art Of Programming
Another parallel between user interfaces and code: nobody reads the fantastic manual. For this reason good code is self-explantory, just as a good user interface is self-explanatory.
- Nielsen, Jakob. Usability engineering. Elsevier, 1994. ↩