Showing 12 posts
The time to conclude the CLI design series has come. I hope you have enjoyed the topic and that got some useful tips and tricks for your future developments! Here is the summary of all the topics that were covered: Series introduction The CLI is the presentation layer Error reporting Requesting and offering help Putting flags to good use Do not reinvent option parsing Subcommand-based interfaces Single-command interfaces Handling output messages Screen wrapping Consider interactive prompts twice Stay tuned for the next series!
While it is a rare thing to find, CLI-based applications can be interactive just like any other kind of application can. If you choose to interactively query the user for details in your program or script, you should be aware of the two scenarios that can result from this choice (which, interestingly, are the same scenarios that we already saw regarding output verbosity). The first scenario is about “fast” applications: if the program is expected to complete in a short amount of time—where short is defined as an amount of time in which the user will not context-switch—it is alright to pop up interactive prompts at any point during the execution of the application.
In a world of terminal emulators within graphical environments, there is no longer a “standard” window size. 80x24 is still the default, sure, but it’s trivial for users to resize the terminal. Why does this matter? Consider the most obvious case: the help message of your program. It is incredibly common to see carefully-formatted embedded strings into the program’s code designed to fit within a 80x24 window (which is especially true for the width of the text).
Your CLI-based program has to communicate with the user. The most obvious case is to display error or warning messages, but in some cases it is also to report progress status. There are a few details to be considered in this area. Quietness vs. verbosity by default You’ve probably heard the “No news is good news” principle. This is a major guideline behind the design of most standard Unix tools: when no problems arise, the tool just does what it was asked for and does not print anything on the screen.
In the previous post, I provided common guidelines on how to implement a subcommand-based interface. It is now the time to look into the interface of those applications that implement a single command or function, which are actually quite abundant. Without going too far, you will encounter cp, ls and sudo, all of which are just a tiny sample of tools that fit this model. General syntax The general syntax of a single-command interface is simple:
Subcommand-based interfaces are common: the majority of the CLI tools that provide more than one operation within them expose their features in this manner. Examples of such interfaces include svn, git, ifconfig, yum, apt-get and many, many more. Designing the interface of these applications is quite straightforward once you have the concepts clear, but there are quite a few common pitfalls that you need to be aware of to prevent falling into them.
In the previous post, we saw what good and bad use cases for flags in the interface of a command-line application are. We talked about the theory, so it is now the time to talk about the implementation details. The point I want to make in this post is simple: do not reinvent option parsing. Use the libraries provided by the platform you are targeting to implement the interface of your application: even if there is some little detail of the library that you don’t agree with, consistency with the platform is lightyears better than a custom implementation that fails to handle some corner cases and/or behaves in an unexpected manner.
As the Wikipedia puts it in its Command-line interface page: A command-line option or simply option (also known as a flag or switch) modifies the operation of a command; the effect is determined by the command’s program. Yet, many developers abuse flags to do many unrelated things and therefore end up providing a non-standard and confusing user interface. Let’s take a look at some specific use cases, both bad and good.
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.
Error reporting is a tricky business. Get it right and your users will be able to correct their actions quickly. Get it wrong and you will be the cause of your user’s frustration — because, face it: A) users will make mistakes and B) your application will encounter erroneous conditions due to bugs or unpredicted scenarios. Understand usage errors and application errors From the programmer’s point of view, there are many types of errors that an application can detect; but, from the point of view of the user, errors can be classified in two broad categories: usage errors and application errors.
Treat the code that implements a CLI utility to the highest standards. Let’s step back for a moment. In any graphical application, there always is a chunk of code to deal with the interface of the tool and there is another chunk of code to do the “real work” behind the interface, possibly split into multiple logical layers. This basic split of presentation vs. logic is essential for the maintainability of the code.
Ready for a new series? Having just gone over a bunch of items regarding code readability, it is time to shift gears and get into the topic of the design of Command Line Interfaces (or CLIs for short). The main focus of this series will be to cover best practices involved in creating applications whose interface is command-line oriented. Among other things, I will detail how the CLI should accept optional and required arguments, how a tool should expose more than one action and how interactive help should be handled.