I’ve been thinking about the usability of command-line terminals a lot recently.
Command-line interfaces remain mystifying to many people. Usability hobbyists seem as inclined to ask why the terminal exists, as how to optimise it. I’ve also had it suggested to me that the discipline of User Experience (UX) has little to offer the Command-Line Interface (CLI), because the habits of terminal users are too inherent or instinctive to be defined and optimised by usability experts.
As an experienced terminal user with a keen interest in usability, I disagree that usability has little to offer the CLI experience. I believe that the experience can be improved through the application of usability principles just as much as for more graphical domains.
Steps to learn a new CLI tool
To help demystify the command-line experience, I’m going to lay out some of the patterns of thinking and behaviour that define my use of the CLI.
New CLI tools I’ve learned recently include snap
, kubectl
and nghttp2
, and I’ve also dabbled in writing command-line tools myself.
Below I’ll map out an example of the steps I might go through when discovering a new command-line tool, as a basis for exploring how these tools could be optimised for CLI users.
- Install the tool
- First, I might try
apt install {tool}
(orbrew install {tool}
on a mac) - If that fails, I’ll probably search the internet for “Install {tool}” and hope to find the official documentation
- First, I might try
- Check it is installed, and if tab-complete works
- Type the first few characters of the command name (
sna
forsnap
) followed by<tab> <tab>
, to see if the command name auto-completes, signifying that the system is aware of its existence - Hit space, and then
<tab> <tab>
again, to see if it shows me a list of available sub-commands, indicating that tab completion is set up correctly for the tool
- Type the first few characters of the command name (
- Try my first command
- I’m probably following some documentation at this point, which will be telling me the first command to run (e.g.
snap install {something}
), so I’ll try that out and expect prompt succinct feedback to show me that it’s working - For basic tools, this may complete my initial interaction with the tool. For more complex tools like
kubectl
orgit
I may continue playing with it
- I’m probably following some documentation at this point, which will be telling me the first command to run (e.g.
- Try to do something more complex
- Now I’m likely no longer following a tutorial, instead I’m experimenting on my own, trying to discover more about the tool
- If what I want to do seems complex, I’ll straight away search the internet for how to do it
- If it seems more simple, I’ll start looking for a list of subcommands to achieve my goal
- I start with
{tool} <tab> <tab>
to see if it gives me a list of subcommands, in case it will be obvious what to do next from that list - If that fails I’ll try, in order,
{tool} <enter>
,{tool} -h
,{tool} --help
,{tool} help
or{tool} /?
- If none of those work then I’ll try
man {tool}
, looking for a Unix manual entry - If that fails then I’ll fall back to searching the internet again
UX recommendations
Considering my own experience of CLI tools, I am reasonably confident the following recommendations make good general practice guidelines:
- Always implement a
--help
option on the main command and all subcommands, and if appropriate print out some help when no options are provided ({tool} <enter>
) - Provide both short- (e.g.
-h
) and long- (e.g.--help
) form options, and make them guessable - Carefully consider the naming of all subcommands and options, use familiar words where possible (e.g.
help
,clean
,create
) - Be consistent with your naming - have a clear philosophy behind your use of subcommands vs options, verbs vs nouns etc.
- Provide helpful, readable output at all times - especially when there’s an error (
npm
I’m looking at you) - Use long-form options in documentation, to make commands more self-explanatory
- Make the tool easy to install with common software management systems (snap, apt, Homebrew, or sometimes NPM or pip)
- Provide tab-completion. If it can’t be installed with the tool, make it easy to install and document how to set it up in your installation guide
- Command outputs should use the appropriate output streams (STDOUT and STDERR) and should be as user-friendly and succinct as possible, and ideally make use of terminal colours
Some of these recommendations are easier to implement than others. Ideally every command should consider their subcommands and options carefully, and implement --help
. But writing auto-complete scripts is a significant undertaking.
Similarly, packaging your tool as a snap is significantly easier than, for example, adding software to the official Ubuntu software sources.
Although I believe all of the above to be good general advice, I would very much welcome research to highlight the relative importance of addressing each concern.
Outstanding questions
There are a number of further questions for which the answers don’t seem obvious to me, but I’d love to somehow find out the answers:
- Once users have learned the short-form options (e.g.
-h
) do they ever use the long-form (e.g.--help
)? - Do users prefer subcommands (
mytool create {something}
) or options (mytool --create {something}
)? - For multi-level commands, do users prefer
{tool} {object} {verb}
(e.g.git remote add {remote_name}
), or{tool} {verb} {object}
(e.g.kubectl get pod {pod_name}
), or perhaps{tool} {verb}-{object}
(e.g.juju remove-application {app_name}
)? - What patterns exist for formatting command output? What’s the optimal length for users to read, and what types of formatting do users find easiest to understand?
If you know of either authoritative recommendations or existing research on these topics, please let me know in the comments below.
I’ll try to write a more in-depth follow-up to this post when I’ve explored a bit further on some of these topics.