In fact this question is about cautions to be taken to enhance quality user experience and reduce avoidable support calls.
A lack of proper input validation is one of those things which tends to lead quite quickly to users doing "bad" things with your application, when it should really be handled by the programmer.
I've seen legacy apps where users have been trained to:
- not enter apostrophes in names
- not enter any symbol other than
- ensure there are no spaces before or after the text they've entered
- check that a correctly formatted email address is being entered in to the
- make sure "
http://" is put before web addresses
All of the above issues are ones which should be handled by an application developer. When your input validation is essentially "make sure the user knows what format this field should be in and trust what they've entered is right", then unexpected things are bound to find their way in to the app. Aside from the obvious security implications, users make mistakes. As programmers we often produce our best products by bending over backwards to make sure that the user can't get it wrong, no matter how hard they try!
I once got a customer support call because my app just disappeared. Turned out they opened another app on top of it.
... I decided not to ensure that didn't happen again, since it was the users computer illiteracy that caused the problem, not the app. Anything I could have done to fix it would have lead to a poor user experience for others.
Almost every program that I write is invoked strictly from the command line. I've also written some fancier things that started out as CLI interfaces and rapidly grew into something more shell like than anything.
So, I can speak only for what I know. Here's some common issues with command line programs:
Way too many options
Unless you are writing a compiler or a line editor, try to keep options limited to one screen full on an 80x25 frame buffer when
/? is passed. It is perfectly fine to have more options than that, but break them into sub categories. For instance
foo --help option_name
No long options
It is much easier to remember
foo --attach_to [argument] --volatile --verbose than it is to remember
foo -a [arg] -v +V. This isn't always possible, but in most cases, it is.
No input validation
Almost every platform has multiple libraries that are tried, tested and true when it comes to parsing and validating arguments. Almost every platform has a tried, tested and true lexer that validates input from a CLI. Use one, the other or both. If your program segfaults or divides by zero due to something a user provided, that's just embarrassing.
You might not need something as complex as a lexer, perhaps you can just tokenize the string if you are expecting stuff in a certain order with certain things in certain places.
I actually got a bug report once where an integer was expected and someone typed
f*** my life in quotes. I didn't write that program, I had the misfortune of inheriting it.
No 'verbocity' knob
Allow experienced users to easily discover how to get way more noise out of your program than most people would tolerate, but default to printing serious and critical stuff only. I can't tell you how many times I had to fire up
strace just to realize that something segfaulted because it operated on a NULL file stream.
You can also wrap assertions so that turning them off via NDEBUG or other means still results in something printed or logged for the user to find.
Speaking of log files, try to make sure anything you place in them makes (at least a little) sense to someone other than you. If the start of every entry is a UNIX epoch date, you're going to compound frustration in someone who really wants to help you reproduce the bug.
No 'bug buddy' in debug mode
A lot of programs offer some sort of 'debug' switch that offers extra chatter regarding what is going on with the program, but very few offer the following:
- A way to automatically send a report via HTTP/HTTPS and get some kind of service reference number
- A way to dump useful information to a file that could be sent as an attachment to a support request
Or, perhaps you like hearing people read the following over the phone:
It says unexpected condition at zero eff oh four zero oh .... OK lemme read that back to you ...
Overly complex configuration files
Don't justify the need to parse a config as an excuse to get a buzz on lots of syntactic sugar. Try to use a format that people actually know, even if it means extra work when parsing. I try to use the INI style format whenever possible. You'd be amazed what you can pull off with a simple key->value dictionary.
No configuration files
Don't make people write shell scripts or batch files just to use your program, unless it was intended to be a tool for either task. Give me a means to point at a file containing my usual options and provide just a few additional arguments.
No 'wet floor' signs
If some feature could get the user into trouble (perhaps it is there for advanced users), clearly mark it as such. Additionally, if someone fat fingers input or forgets something, have you program print a very friendly link to on-line documentation. You might be dealing with someone who is using your program via KVM and can't cut and paste.
When possible, (this coincides with input validation) use the Google apporach:
Did you mean foo --bar FILENME, you typed only foo --bar
Offer a way out of destructive instructions
The goal is to tell the user why it didn't work and have them try a few more times, while ensuring that you do nothing potentially destructive unless it appears that the user really wants you to do that. Allow a switch that turns off 'nagging' , for instance
/Y but otherwise allow a way out for someone who simply has 'fat fingers'.
I'm probably forgetting a few pointers. I deal with this frequently as it is very, very difficult to make the 'low level' interface for something intuitive enough for most people to avoid making mistakes.
"Are you sure you want to delete this file/record? Yes/No". Clicked yes and then got a call that it "mistakenly" clicked the red delete button and it needs that data back:)
I don't feel like getting specific break/fix examples is as important as realizing this:
- Users do not read your manual, or watch your tutorials. They learn your software through exploration.
If through that exploration they break something, as a programmer it is your job to either warn them of the danger or prevent it from happening in the first place. I can't remember where I saw it now, but in the back of my mind I always try to "make doing the right thing easy" for the user of my software.
If you insist on examples:
- User was able to enter a lowercase name that broke the integration code / fixed by performing input validation
- User was able to click the wrong button after performing an action / fixed by only showing the correct buttons.
- User was able to do X accidentally / fixed by warning them they are about to do X.
See where this is going? :)
Here is one I heard this week. A user asks for a feature "send me a notification when an event occurs". Simple enough and the developer goes ahead and implements it. Sure, the first question should have been "what are trying to address by this notification?". I won't go into that. Few days later the user stops by the developer and asks "I got this notification. What am I supposed to do with it?".
I remembered this Dilbert comic and suggested to the developer "write an app to figure out what the user should do with that notification".
Like mpeterson said, the user is very competitive in their area of expertise. They just don't think like a software developer or designer.
I don't think users are stupid. They don't want to use your or any program at all. All they want is to get their things done. Help them and prevent harm from happening to them along the way.
Having a good user interface and providing an adequate learning experience goes a long way towards preventing users from doing bad things.
Good user interfaces should be frictionless.
Instead of throwing up a dialog box (an expensive operation, and one that users ignore after awhile) to confirm a delete, perform the delete, and offer a way to undo.
Good user interfaces should be discoverable.
Although the ribbon in Microsoft Office gets a lot of flak because it forces old users of Word to change their ways, the ribbon is a shining example of how you can make an interface discoverable (i.e. easy to discover).
Good user interfaces, like good code, should be self-explanatory.
Nobody reads the manual. The only manual I ever got my users to read was a PowerPoint presentation containing step-by-step walkthroughs of the software. I have seen these done with video tools like Camtasia, but PowerPoints are better because you can easily flip backwards and forwards through the steps.
User don't make mistakes. The mistakes lie with the programmer who failed to create a usable interface.
So do usability tests with each release!