Make your applications invincible
The name of the first programmer to ever code a popup window telling a user that they had made an error is undoubtedly lost to history, but the impact of that one simple choice resonates even today. That early coder, faced with the difficulty of building software set a dangerous and counter-productive precedent we as a community have internalized to our detriment.
It created an adversarial dichotomy between developer and user, based on the false assumption that such a thing as a “user error” exists. It does not.
There is no such thing as a user error. There are only interactions that we developers have not adequately anticipated and designed for. How do we correct this?
Avoid Tunnel Vision
Step 1 of the programmers’ process involves defining our problem set. What does this application need to achieve? We define the necessary functionality, the implicit data structures, the communication layers, and the user interface. Unfortunately, we do this in a vacuum.
We get so focused on how to achieve the desired result that we fail to account for the journey the user undergoes to get there. This is understandable as quite often we’re facing an immensely difficult task and finding even 1 adequate solution can be daunting, but this kind of singular approach is a recipe for myriad possible failure states. We must learn to account for unexpected user choices or our code won’t know how to handle them when they happen, and they always happen.
Appropriately Restrict User Input
If you’ve ever uttered the sentence “No, you’re not supposed to do that…” when showing a user your application, you’ve failed them. If a user isn’t supposed to do something, then your code should stop them from being able to do it. The responsibility for effective interaction rests solely on the developer.
Web forms present an excellent example of this in practice. Does the data you collect need to be in a specific format? Enforce that as the user fills it out. Give users hints in placeholder text or labels about the way you need their information, then write validation code that checks and enforces their entries to match it. Email addresses, dates, and phone numbers all present opportunities for a user to exercise their own judgment in format, and often that won’t match what your code wants.
Test With Real Users
We’re programmers, and as such we understandably think like programmers. Most of the rest of the world does not. In my experience, the majority of testing that happens to code is done by the person writing it. Although understandable, it is an amazingly ineffective way to objectively test software. You already know how your code is supposed to work, and you already know how you’d solve the problem at hand so inevitably your interactions with your application will reflect that.
Having colleagues test your code is marginally better, but still a hollow facsimile of how an actual person will use your software as they are also programmers with an entire knowledge set the average user will not have.
It can be intimidating and even heartbreaking, but having even 1 real user test your application will provide far more useful information than all of your own testing combined. You may learn something you’re very proud of does not work well for the user, or that your UI is cluttered and confusing to them; this moment sucks, but it’s worth it, I promise you.
Effective development requires a willingness to confront some brutal truths. Things you take for granted will render users lost and frustrated when trying to navigate your app. Carefully considered choices you’ve made about user interfaces will turn out to be completely wrong in practice; that’s just part of the game.
Pride can and does kill in development. If your honest goal is to build the best, most effective solutions possible for your users, then you must subjugate your assumptions and listen to them. You have to imagine the things they’re not saying, and build solutions in advance. You will fail in some of these aspects.
The beauty of development is that you can always fix these shortcomings. Software has versions for a reason and you can revise and enhance as you learn what works best. The best developers always do.
Eliminate the idea of a “user error” from your memory. Replace it with a willingness to understand your user and you will build things that people love and use. You’ll never anticipate every potential problem before it arises, but hey, thats what version 2.0 is for.