views:

226

answers:

2

What patterns contribute or detract from the usability of a CLI interface?

As an example consider the CLI for ClearCase. The CLI is very comprehensive (+1) but it is has several glaring opportunities. Recently, I wanted to force the files to lower case into ClearCase using clearfsimport. Unfortunately I wound up on the documentation for its cousin clearimport. It may seem slight but it cost me more hours than I care to admit. The variation in the middle got me.

Why provide such nearly identical functionality with such nearly identical names? There are many better options in my opinion

  • clearimport -fs
  • fsclearimport
  • clear_fs_import
  • clearimport_fs

Anything would be better than what they went with. The code I am working on IS a CLI and this experience made me look at my own choices. I think I have all the basics covered (standard help, long-form vs short-form, short meaningful names, providing examples, eliminate ambiguity, accurately handling spaces within quotes, etc). There is some literature on this subject. Perhaps a bad CLI is no different than a bad API. CLI are type of an API in some sense. The goals are naturally common:: flexibility, readability, and completeness. Several factors differentiate CLI from a typical API. One is that CLI needs to support scriptability (participate many times perhaps in a series of pipes). Another is that autocompletion and namespaces don't exist in the same way. You don't always have a nice colorful GUI doing stuff for you. CLIs must document themselves externally to customer directly. And finally the audience of a CLI is vastly different than the standard API. I appreciate any insight you may have.

+6  A: 

I like the subcommand pattern, which I'm most familiar with as its implemented in the command-line Subversion client.

svn [subcommand] [options] [files]

Without the subcommands, subversion would have waaaaay too many different options for me to remember them effectively, and the help system would be a pain to slog through.

But, if I don't remember how any particular subcommand works, I can just type:

svn help [subcommand]

...and it shows me only the relevant portions of the help documentation.

benjismith
Do you find the supporting both types extra confusing?
ojblass
Well, I've never *written* software that uses the subcommand pattern. So I don't know much about supporting it, from an authorship perspective. I just know, as a user, that I've found it very convenient.
benjismith
I totally agree. Even though "svn update" is longer to type, I find it much easier to remember than the hypothetical "svn -u". And I don't use the svn command line often.
SealedSun
Subcommands rock.
Daniel Straight
+2  A: 

As noted above, this format:

 [master verb] [subverb] [optionally, noun] [options]

is good in terms of remembering what commands are available. cvs, svn, Perforce, git, all adhere to this. It improves discoverability of commands, a major CLI problem. One wrinkle that occurs here is options for the master-verb vs. options for the subverb. I.e.,

cvs -d dir command bar

is different than

cvs command -d dir bar

This was a confusing situation in cvs, which svn "fixed" by allowing options specified in any order. Your own solution may vary; if you have a very good reason to pass options to the master verb, okay, just be aware of the overhead.

Looking to API usability is a good idea too, but beware that there is no real typing in CLI commands, and there is a lot of richness in what CLI commands 'return', since you've got both a return code and an output to work with. In the unixy/streams world, the output is usually much more important than the return code. Getting the format of your output right is crucial. Also, while tempting, I've found that sending different things to stdout vs. stderr is not always useful; it confuses novice and even intermediate users (because they both get dumped to console in most cases), and rarely is useful advanced users. So unless there's a real need for it I avoid it; it's too easy for (e.g.) someone to get very confused about why the output of a command was '' in an error condition just because the programmer nicely dumped the errors to stderr.

Another issue in design is the "what next" problem. In a GUI, the next steps for the user are spelled out by the available buttons, menus, etc. In a CLI, the user can literally type any command next, and pipe any command to any other. (Or try, at least.) I design my commands to give hints (either in the help or the output) as to what potential next steps might be in a typical workflow.

Another good pattern is allowing user customization of the output. While it is possible for users to use cut, sort, etc. to tailor the output, being able to specify a format string magnifies the utility of a command. The example I cite here is top, which lets you tell it which columns you want.

Alex Feinman