This article is part number 4 of the CLI design series.


Any CLI application must offer help to describe its command line syntax: the flags it supports, the subcommands it implements, the meaning of the positional arguments, etc. Failure to do results in an application that is completely unusable: unlike GUI applications, the interface of CLI tools is not discoverable without instructions.

It is, therefore, important to realize that help does not only exist to aid the user in recovering from errors. Help also exists to teach users how the application works, what the expectations are and, more importantly, to showcase the features of the program.

There are two major ways in which to provide such information and lots of minor variations in between these two extremes: on the one hand, we have the inclusion of a comprehensive builtin help system and, on the other hand, we have a simple and terse pointer to the complete and up-to-date manual page. Obviously, providing a builtin help system is more complex than just offering a pointer to a manual page, and for that reason we will focus most of the recommendations below on the former case.

Only show help when explicitly told to do so

Long help messages should only be shown when the user explicitly requests them. Many application developers fall into the trap of trying to be too helpful and miserably failing at that. How so? When the user makes a usage mistake, the application greets him with the error details and then dumps the whole builtin help messages on the screen. After all: the user made a mistake, so why wouldn’t he want to read everything about the interface? Well, he probably won’t. This actually causes the opposite result because receiving a long help message is quite an annoying and unexpected behavior. Let’s see why.

Builtin help messages tend to be long and cause the screen to scroll upwards significantly, possibly pushing precious information over the top. If the application prints such a long help message after printing the error that the user made, the most obvious consequences are: first, that the command that the user typed and the associated error message get lost above the top of the screen and thus cannot be easily read (assuming the user knows how to scroll up, or else they won’t be noticed at all!); and, second, reading long messages on the command line without a paging program is difficult. None of these make the experience pleasant and, even worse, hinder the debugging of the problem that the user is experiencing.

Again, as I mentioned in the previous post: an experienced user will want a terse message describing exactly the mistake he made while a novice user will probably want that and also a pointer to further help. All this information can be conveyed in two lines, and thus you should not use more than that.

Never send help messages to stderr

If you follow the previous guideline, you now know that the builtin help of an application should only be shown when explicitly requested by the user. Because the user is explicitly requesting help, the intended consequence of his application invocation is to receive help. Help is not a side-effect nor an error. Therefore, it’s just plain wrong to send the help messages to stderr, both conceptually and practically.

There are very few things as frustrating as invoking frobmaker help | grep create to see anything related to frob creation, only to be greeted by a giant, unfiltered set of messages on the screen. Users want to grep your help messages; don’t make that difficult.

Help must be up-to-date and accurate

Misleading information is harmful. If you choose to implement a builtin help system in your program, make sure that its contents stay relevant, are up-to-date and, more importantly, are extremely accurate — especially when detailing the various options and arguments that the program supports. If you choose to (only) provide a manual page, make double-sure that it remains accurate as well.

The good news is that keeping the builtin help system up-to-date and accurate is, usually, easier than keeping external documentation in sync with the code. After all, when you are changing the code, it’s easier to change any user-facing information right there than knowing that there is a secondary place that needs updating and doing the matching changes there as well.

But, on the other hand, we have all seen applications with inaccurate help messages that lack supported options or mention subcommands that have long been removed! Mistakes do happen, especially when the code is maintained by more than one person and not everyone is as careful and detail-oriented as you are.

My suggestion to resolve this situation and prevent it from happening altogether is to use a library that allows you to implement and document the syntax of your command line programmatically. Usually, such a library provides abstractions to represent the various components of the command line, and keeping their associated documentation in sync with the existence of each component is much easier than dealing with separate entities. No: neither getopt(3) nor getopt_long(3) make the cut. You need something at a higher semantical level that is possibly (and hopefully) built on top of these two; most high-level toolkits provide such functionality, and most standard libraries in high-level languages do too. But if not, and your application is non-trivial, spend some time rolling your own.

Remember: help is important!

Mastering the skills to implement a good help system in your application is extremely important: even if your interface ends up being non-standard and/or confusing, having a good and discoverable help system means users will still be able to interact with your tool. A good help system minimizes user frustration and shows the amount of care that went into the development of your application.

So, don’t leave the help system and/or the documentation aside. Continuously spend time on these to make your software package cleaner overall.

Comments from the original Blogger-hosted post: