Conventional thinking has it that “user interface design” references a graphical user interface such as a desktop, web or mobile application. But over the last few years I’ve become increasingly aware of how important it is to consider user interface design for command line utilities as well.

It’s true that the interface (and implied software implementation) for command line utilities is much simpler than even simple graphical user interfaces, but in my experience it is still fundamentally true that poor interface design results in command line utilities that are difficult to use or difficult to maintain (often both). Difficult to use utilities become a disincentive to adoption; users quickly become frustrated and may either revert to an old way of doing something, or re-invent the effort and try to find another utility to do what they need.

For this reason I am currently taking a User Experience course through Algonquin College and I’m really enjoying the learning process and insights I’m acquiring as a result.

So let’s take a look at some guidelines on User Interface Design.

Keep the interface simple

For a command line utility, for me this embodies the unix philosophy of “do one thing well”; that is, small utilities that focus on doing one thing very effectively. In this context you could also say that a utility that becomes complex with lots of options or sub-commands is a code-smell (utility-smell?) that you might be able to refactor into multiple utilities for simpler use.

Create consistency and use common UI elements

A common complaint about the git command is that the various sub-commands often embody the same or similar concepts in completely different ways.

For example

# delete a tag; using "-d" argument
git tag -d <tagname>

# delete a branch; using "-D" argument
git branch -D <branchname>

# delete a remote; using "remove" sub-command
git remote remove <remote name>

# delete a stashed commit; using "drop" sub-command
git stash drop <stashid>

Some of those differences you could reasonably argue are necessary such as the queue metaphor for git stash, but there’s no question that having to re-think the necessary argument for the “delete” function for each sub-command is jarring, and increases friction to quick adoption. Recent git releases have begun normalizing arguments across the various sub-commands so the above examples do represent a historical “worst case”.

Be purposeful in page layout

Admittedly it’s a bit tricky to re-interpret this one for a command line utility. But I think you could let these items fall under this category:

  • Be mindful of the logging layout on the console (or to a file)
  • Do the logging messages contain sufficient information, such as timestamps, to be useful to the user?
  • Use indentation and line spacing to effectively communicate hierarchy, or related concepts.

Strategically use color and texture

For me using git took a big step forward in the last few years when they used color coding on the console to indicate various status levels in relation to data being reported; red for a problem or warning, green for ok.

Use typography to create hierarchy and clarity

There’s usually not many choices here for a command line utility, but you can use ALL CAPS to highlight information along with color coding. Or if you are not limited to ASCII, there are special characters that can be used such as used in the tree utility, or you might be able to get creative with ASCII art.

.
├── directory1
│   ├── file1
│   ├── file2
│   └── subdir
├── directory2
│   └── file3
└── file4

Make sure the system communicates what’s happening

Make a distinction between logging and status messages. In a command line utility, especially one that might take some time processing, it’s probably really useful to the user to have regular console messages indicating what’s happening, that stuff is still happening and not locked up in some way. In comparison, warnings or diagnostic messages for posterity in case something goes wrong are less likely to be useful on the console, and more likely to be useful in a file that can be reviewed if something unexpected occurs and perhaps submitted as a support request package.

Depending on the context of your utility, it may be appropriate to have your log messages directed to the console and the logging level controlled with a command line option. In this case take care that the default log level covers the appropriate verbosity of status messages, and that debug or detailed messages are constrained to the “high verbosity” logging levels.

Think about the defaults

  • Is the default logging level appropriate (too much, or too little detail)?
  • Does the set of default settings best represent the main use case of the utility, or the bulk of users?

And, of course, keep in mind that arguments with defaults imply that they are also optional arguments rather than mandatory arguments. Maintain the conventions for your environment relating to mandatory and optional command line arguments; in POSIX optional arguments are the “single dash” or “double dash” arguments.

Conclusions

I’ve walked through seven items relating to user interface design and shown how they can be expressed in command line utilities. Hopefully you found the scenery interesting.