Program Eloquence Considered Harmful
tilde.team
tilde.team
My priorities for errors are:
- enough context to find the error and possibly further information
- consistent formatting so users can learn pattern recognition. Powershell is much better at this than Unix tools because the shell displays errors
- error message should fit on one screen and little but the relevant error should be printed after an interactive command
Terseness is mostly relevant for non-interactive use such as log files that need to be read quickly.
Also the Rust compiler's output quality isn't due to the length of the output, it's just formatted very well and has often very useful hints thanks to the compiler's insight into types and ownership. In the world of NodeJS, TypeScript etc. I've seen a fair share of verbose error messages, mostly consisting of worthless but colorfully formatted information that only makes it harder to find the actually useful part.
$ cat invalid
cat: invalid: invalid path
An invalid path or a file not found are not the same thing! The real danger is that being too terse and unclear is worse than unnecessary verbosity.However, there are some problems with entire thinking:
- When you are looking into results of larger set of operation (i.e. scripts) you may need more info to easier grasp the context
- Did you see it already ? There is no need for verbosity once you experienced a problem recently (which is what happens most of the time)
The errors deserve both variants, short and terse, just not on the same place (I don't want spams in terminal or logs). Short variant should provide some form of id that can be looked at for more details:
cat(e123): file not found
e123 could be searched in detailed error message document.
cat is just passing along the error string from the libc/system call it used. That error string is standard-ish over most libcs; some unixs can read directories as if they were files.
Changing that message would require significant additional complexity in cat which probably isn't useful.
I was reading through the article waiting for the connection to eloquence and was disappointed when minimalism was in its place.
I hugely agree with the thrust of this article, but this Google example might be a mistake to include. It’s the only lay-person example here, not a shell or programming language for technical people. Showing a Google query back to a user, I might speculate, has an important function of allowing users to see spelling errors they didn’t know they typed. I can imagine other reasons as well, and I’d be willing to bet that Google has tried both and decided on repeating the output. The other thing not discussed is the Google output is organized hierarchically, separating the error from the tips, and bolding the search query. Those two things could dramatically improve the PowerShell output, for example, without removing any text. No other example had style formatting, and good styling and layout can be as effective as silence.
For example, a typical run of shellcheck might look something like this:
~/test> shellcheck blah.sh
In blah.sh line 2:
echo $1
^-- SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
echo "$1"
For more information:
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
https://github.com/koalaman/shellcheck/The author's arguments might work if there's some obvious place to go for more information. I'd take "invalid path: check ~/cat_error_log for more."
But I think terseness is an imperfect proxy for clarity. In the Google search example, repeating the search query to the user may be actually useful. They may have pasted something by accident and/or heavily mistyped and not even have noticed. Do include important information, so the user can go directly to the place of fault. State what is wrong and try not to have the same message for many unrelated errors.
By the way, I'm still waiting for an "Unreasonable effectiveness of X considered harmful" article.
More thorough error messages can be good, but they need to be well formatted to help people's eyes lock on to the core message; then they can read more if they need to.
One thing I like about Python's error messages is that, even though you can get a long trace, the most specific/relevant information is usually at the bottom, right next to your prompt. I tell me students, "read your Python error messages from the bottom up."
Assuming users are 'too dumb' or 'smart enough' sounds like a broad generalization that's highly dependent on the tool.
I'm glad we have verbose compiler errors, and I write C++ for a living. Am I too smart for verbose output?
My grandmother can't login in to Facebook, should we forego the error dialogs because she's not going to read them?
I believe that terse error messages have their place, but this article over generalizes and is full of personal preference rather than data driven conclusions.
Asking whether they are sure they want to continue has added context to make someone think twice about whether they are really connecting to the correct host.
Likewise, repeating the host address again after confirmation makes an error more likely to be spotted if it's off slightly (think along the lines of spaced repetition helping memorise things).
One assumes an audience for the error message. Unix definitely assumes expertise. Windows assumes a neophyte. Given that something has gone wrong, the question is the shortest path to a remedy.
> For one thing, repeating the entire search query in bold isn't necessary. The user already knows what they searched for.
Echoing the input is useless. But if the program is interpreting the input somehow (like there are keywords or commands allowed), then showing the user what the program understood could be critical to finding the problem.
The argument of "the user" is similar to that for "the web user" where web design is mostly about not making people think. You want them getting to what they want as fast as possible, so no reading, no extra activities, get them to their goal... because that usually means a transaction.
In this case, we should also get the user to their goal. Which is different from that of a web user. The goal here should be to give the "user", which is mostly going to be a developer or someone trying to perform an action, the best possible info on how to accomplish that action and what went wrong the time before that.
So that they can see what needs to change immediately and there should be no 2nd time with yet another error message.
The context is different, but both approaches are about best serving the user in their respective context.
$ cat 'the can of toona'
cat: cannot open: the can of toona g++ -fmax-errors=1
is usually enough. Sometimes you forget a brace and it's the last error. But sometimes you really need to paw through all those errors.Controllable verbosity is best practice. Quiet defaults are nice though
In logs this can be partially achieved by logging additional details with a low logging level. With errors coming from exceptions in particular, I like to log the error message (exception message) separately from the stack trace for that reason.
Back when I was doing desktop GUI apps full time, my standard pattern was to display a terse and readable error message, and provide a link the user could click to bring up a much more detailed error report. The more detailed report was purely for the benefit of tech support, and very, very few users would click it unless specifically told to.
I'm no Web developer, but I imagine the equivalent for a Web app would be to display a terse error in the browser and save a verbose error in the logs.
Services like Bugsnag are designed for this use case. You can send them an error message with arbitrary JSON attached (cause of error, but also details on the logged in user, device, browser, etc). And then yes, generally a generic "Try again or contact support" error message presented to the user. It works quite well if/when they do contact support because you can lookup specifically what errors have been triggered by that user.
Of course anything is better than nothing. When I took over this codebase its error handling strategy was "Don't show an error message at all and just keep retrying until it works". Which was fine for transient errors, but a nightmare when something did go wrong: the user report would usually be "the loading spinner just keeps spinning forever", and that was all you had to go on. Nightmare.
This is an absurdity. Both methods are valid. Different people want different things from the error messages.
This is most commonly addressed in programs using "verbose mode", often with multiple levels of verbosity ( -vv or -vvv ).
Another type of error message which I wish was a required standard is to output structured error messages in the form of JSON containing all the relevant bits of information. It is very annoying to have to parse apart error messages coming from a tool being called programatically.