Home Programming Building Modern CLI Applications in Go

Building Modern CLI Applications in Go

By Marian Montagnino
ai-assist-svg-icon Book + AI Assistant
eBook + AI Assistant $35.99 $24.99
Print $44.99
Subscription $15.99 $10 p/m for three months
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime! ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Along with your eBook purchase, enjoy AI Assistant (beta) access in our online reader for a personalized, interactive reading experience.
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription. BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime! ai-assist-svg-icon NEW: AI Assistant (beta) Available with eBook, Print, and Subscription.
eBook + AI Assistant $35.99 $24.99
Print $44.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
Gain access to our AI Assistant (beta) for an exclusive selection of 500 books, available during your subscription period. Enjoy a personalized, interactive, and narrative experience to engage with the book content on a deeper level.
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Along with your eBook purchase, enjoy AI Assistant (beta) access in our online reader for a personalized, interactive reading experience.
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Chapter 1: Understanding CLI Standards
About this book
Although graphical user interfaces (GUIs) are intuitive and user-friendly, nothing beats a command-line interface (CLI) when it comes to productivity. Many organizations settle for a GUI without searching for alternatives that offer better accessibility and functionality. If this describes your organization, then pick up this book and get them to rethink that decision. Building Modern CLI Applications in Go will help you achieve an interface that rivals a GUI in elegance yet surpasses it in high-performance execution. Through its practical, step-by-step approach, you’ll learn everything you need to harness the power and simplicity of the Go language to build CLI applications that revolutionize the way you work. After a primer on CLI standards and Go, you’ll be launched into tool design and proper framework use for true development proficiency. The book then moves on to all things CLI, helping you master everything from arguments and flags to errors and API calls. Later, you’ll dive into the nuances of empathic development so that you can ensure the best UX possible, before you finish up with build tags, cross-compilation, and container-based distribution. By the end of this UX book, you’ll be fully equipped to take the performance and flexibility of your organization’s applications to the next level.
Publication date:
March 2023
Publisher
Packt
Pages
406
ISBN
9781804611654

 

Understanding CLI Standards

The Command-Line Interface (CLI) is a text-based interface for humans, and computer interaction was initially designed as a way of interacting with an Operating System (OS) before the desktop graphical interface was invented. The CLI, as we know it today, was in popular use in the 1960s until the graphical desktop interface was developed a decade later. However, although most computer users are used to the graphical user interface (GUI) and web, there’s been a resurgence of CLI development circa 2017. Popular and new use cases for the retro CLI vary, but its most popular usage is as an additional offering alongside a company’s API for increased platform usage.

In this chapter, you will learn about the comprehensive history of the CLI, what it is today, and a breakdown of its anatomy. You will learn about UNIX’s philosophy and how following its principles will guide you toward the creation of a successful CLI.

By the end of this chapter, you’ll have a deeper understanding of the CLI, how best to design and implement proven, time-tested standards, and why Go, which has become an increasingly popular language, has a compelling case for being the best language to build your CLI.

In this chapter, we are going to cover the following main topics:

  • A brief introduction and history of the command line
  • The philosophy of CLI development
  • Modern CLI guidelines
  • Go for CLIs
 

A brief introduction and history of the command line

The CLI is the result of the evolution of a much broader human-computer interaction, specifically communication and language processing. Let’s begin the story with the creation of the first compiler, which took us from using punch cards to programming languages.

About the history

The first computer compiler was written by Grace Hopper. A compiler was able to translate written code to machine code and lifted the great burden off programmers of the time consumption of writing machine code manually. Grace Hopper also invented the COBOL programming language in 1959. In that era, punch cards were used for data processing applications or to control machinery. They would contain COBOL, Fortran, and Assembly code. The compiler and advancement of new programming languages eased the task of programming.

The same year, the microchip was invented by Jack Kilby and Robert Noyce. Much less expensive, small-scale computers were made possible and, finally, human-in-the-loop, a back-and-forth interaction between the human and computer, became feasible. Computers were now multitasking and time-sharing systems.

At this point, keyboards became the main method of interacting with computers. By the early 1960s, engineers had attached a Cathode Ray Tube (CRT) monitor to the TeleTYpewriter (TTY) machine. This combination of the CRT and TTY was called a glass TTY and marked the beginning of what we consider the modern monitor.

In 1966, the CRT and teletype machine, which combined the technologies of the electric telegraph, telephone, and typewriter, were about to merge with the final missing puzzle piece, the computer. The teletype computer interface was born. Users would type a command, hit the Enter key, and the computer would respond. These were called command-line interfaces!

There were so many more exciting developments that followed, from the invention of ASCII characters in 1963 to the internet in 1969, UNIX in 1971, and email in 1972. Lexical analysis parsers in 1975 played a major part in the development of programming languages. Text-based adventure games provided amusement for the tech savvy by 1977, and the beginnings of the GUI emerged in the 1970s.

A network of these computers would not have been possible if not for the evolution of the telephone. In 1964, the acoustic modulator/demodulator (modem) was used to transmit data between a telephone line and a computer. The acoustic modem brought us the wide area network (WAN), local area network (LAN), and the broadband we know of today. LAN parties peaked in the 1990s and carried on well into the early 2000s.

In 1978, the first public dial-up bulletin board system (BBS) was developed by Ward Christensen and Randy Suess, who also created the computerized bulletin board system (CBBS). With a modem, users could dial into servers running the CBBS software and connect via a terminal program. Throughout the 1980s, BBS’s popularity grew to fantastic heights, and even in the mid-1990s, BBSs served the greater collective market compared to emerging online service providers such as CompuServe and America Online (AOL).

Note

This deeper understanding of the history of the CLI may give you a greater appreciation for what it is. The terminal is a bit of a time machine. The use of many UNIX and DOS commands feels like you’re standing on the shoulders of giants, looking down at the long computing history beneath it.

Introducing the CLI

Based on the history of the CLI, it’s clear to see that it is a text-based interface that allows communication from user to computer, computer to computer, and computer back to user. It requires the same specific instructions and clear language as the earlier machines it evolved from. Now, let’s dig deeper into CLIs to learn about the different kinds, how they are generally structured, and how and why they are used.

Anatomy

For any CLI, regardless of the specific type, it’s important to understand the anatomy of the commands themselves. Without a particular structure, the computer would not be able to properly parse and understand its instructions. The following is a simple example that we will use to distinguish the different components of a command:

~ cat -b transcript

In the context of this example, the UNIX command, cat, is used to view the contents of the file, transcript. The addition of the –b flag tells the command to print the line number next to non-empty output lines. We will go into each component of the command in detail in the following subsections.

The prompt

A symbol on the terminal indicates to the user that the computer is ready to receive a command. The preceding example shows ~ as the command prompt; however, this can differ depending on the OS.

The command

There are two types of commands:

  • Internal commands are commands that are built into the OS shell, stored within internal memory, and execute faster. A few examples include folder and environment manipulation commands, such as cd, date, and time commands. They do not require a search of the PATH variable to find the executable.
  • External commands are commands that are not built into the OS and are only available through software or applications installed by other parties. These commands are stored within secondary memory and do not execute as quickly as internal commands. A few examples include ls and cat. These are usually located in /bin or /usr/bin in UNIX and require a search of the PATH variable to find the executable.

The previous example uses cat as the external command.

Arguments and options

Commands usually take in parameters for input that consist of one or many arguments and/or options:

  • Arguments are parameters that pass information to the command, for example, mkdir test/.

In the preceding code snippet, test/ is the input parameter to the mkdir command.

  • Options are flags, or switches, that modify the operation of a command, for example mkdir -p test/files/.

In the preceding example, -p is an option to make parent directories if needed.

In the example at the start of this section, -b is an optional flag, shorthand for --number-nonblank, which tells the command to print the line number next to non-empty lines, and the filename, transcript, is an argument passed into the command.

Whitespace

For the OS or application to properly parse these commands, arguments, and options, each is delimited by whitespace. Special attention must be paid to the fact that whitespaces may exist within the parameter itself. This can cause a bit of ambiguity for the command-line interpreter.

Take care to resolve this ambiguity by replacing spaces within parameters. In the following example, we replace the spaces with underscores:

cat Screen_Shot_2021-06-05_at_10.23.16_PM.png

You can also decide to put quotes around the parameter, as in the following example:

cat "Screen Shot 2021-06-05 at 10.23.16 PM.png"

Finally, resolve ambiguity by adding an escape character before each space, as in the following example:

cat Screen\ Shot\ 2021-06-05\ at\ 10.23.16\ PM.png

Note

Although whitespace is the most widely used delimiter, it is not universal.

Syntax and semantics

The CLI provides the language for communicating with the OS or application. Thus, like any language, to be properly interpreted, it requires syntax and semantics. The syntax is the grammar defined by the OS or the application vendor. Semantics define what operations are possible.

When you look at some command-line applications, you can see the language being used. Sometimes, the syntax differs between tools; I will go over the specifics later in this chapter, but, for example, cat -b transcript is a command we’ve looked at before. The command, cat, is a verb, the flag, -b, is an adjective, and transcript is a noun. This is the defined syntax of the cat UNIX command: verb, adjective, noun.

The semantics of the command are defined by what operations are possible. You can see this by viewing the options of, for example, the cat command, which are usually shown in the usage section of the help page, which is output when a user uses the application incorrectly.

Help pages

Because the CLI is entirely text-based and lacking in visual cues, its usage may be ambiguous or unknown. A help page is essential to every CLI. To view a list of valid parameters and options, users may run the command followed by the help option, typically -help, --help, or -h. The -h option is an example of an abbreviated shortcut for the help command.

There’s a common syntax used in built-in help and man pages and following this standard will allow users familiar with the standard to easily use your CLI:

  • Required parameters are typically represented within angled brackets, for example, ping <hostname>
  • Optional parameters are represented within square brackets, for example, mkdir [option] <dirname>
  • Ellipses represent repeated items, for example, cp [option]... <source>... <directory>
  • Vertical bars represent a choice of items, for example, netstat {-t | -u}

Usage

The CLI was the first interface between the user and the OS used primarily for numerical computation, but in time, its usage has expanded in many more practical and fun ways.

Let us see some of the uses:

  • Editor MACroS (Emacs), one of the earliest forms of a text editor provided in UNIX, is a CLI in the form of a mini buffer. Commands and arguments are entered as a combination of key presses: either a Ctrl character plus a key or a key prefixed by a Ctrl character and the output displayed within another buffer.
  • Read-Evaluate-Print Loop (REPL) is a Python interactive shell that offers a CLI, and according to its name can read, evaluate, print, and loop. It allows users a play environment to validate Python commands.
  • MajorMUD and Lunatix are just a couple of popular games that were available on bulletin board systems. As soon as programmers could turn CLIs into play, they did, and while these games were entirely text-based, they were certainly not lacking in fun!
  • Modern video games call their CLI a gaming console. From the console, mod developers can run commands to debug, cheat, or skip part of the game.
  • Helper programs often take in parameters to launch a program in a particular way. For example, Microsoft Visual Code has a command-line option: code <filename>.
  • Some CLIs are embedded into a web application, for example, web-based SSH programs.
  • Companies such as AWS offer CLIs alongside their API as an additional way of interacting with their platform.

Last but not least, scripting has allowed engineers to take their CLIs to a more interactive level. Within a shell scripting language, programmers can script calls to the CLI and capture and manipulate output. The output of one command may also be passed as input into another. This makes the CLI a very powerful resource for developers.

Types

There are two main types of CLIs:

  • OS CLIs
  • Application CLIs

OS CLIs

OS CLIs are often provided alongside the OS. This kind of CLI is referred to as a shell. It is the command-line interpreter that sits a layer above the kernel interpreting and processing commands entered by the user and outputting results and a text-based method of interacting with the OS as an alternative to the graphical display.

Application CLIs

The second type of CLI allows interaction with a specific application running on the OS.

There are three main types of ways users may interact with an application’s CLI:

  • Parameters: They provide input to launch the application in a particular way
  • Interactive command-line sessions: They are launched after the application as an independent and text-alternative method of control
  • Inter-process communication: This allows users to stream or pipe data from the output of one program into another

GUI versus CLI example

Let’s give a clear example of how the CLI can reign over the GUI in speed. Suppose we have a folder full of screenshots. The names of each contain a space and we’d like to rename these files to replace the whitespace with an underscore.

GUI

With a GUI, there’d be several manual steps for renaming a folder full of screenshots that contain whitespaces throughout the filename. Let’s show these steps within macOS, or Darwin:

  1. First, we’d need to open the folder containing all the screenshots:
Figure 1.1 – Folder containing the screenshots where each filename contains numerous spaces

Figure 1.1 – Folder containing the screenshots where each filename contains numerous spaces

  1. Second, we’d press the control button and left-click on a filename, then from the context menu that pops up, select the Rename option.
Figure 1.2 – From the context menu, click on the Rename option

Figure 1.2 – From the context menu, click on the Rename option

  1. Finally, manually replace each of the whitespaces with an underscore.
Figure 1.3 – Replaced whitespaces with underscores in filename

Figure 1.3 – Replaced whitespaces with underscores in filename

Repeat steps 1-3 for each file in the folder. We’re lucky this folder only contains four screenshots. It can quickly get repetitive and tiresome with a folder of more files.

CLI

Let’s see how much faster the CLI can be. Let’s open the terminal and navigate to the folder with the files:

cd ~/Desktop/screenshots/

Let’s view what currently exists in the folder by typing the ls command:

mmontagnino@Marians-MacBook-Pro screenshots % ls
Screen Shot 2022-12-20 at 10.27.55 PM.png
Screen Shot 2022-12-20 at 10.32.48 PM.png
Screen Shot 2022-12-26 at 5.24.48 PM.png
Screen Shot 2022-12-27 at 12.08.12 AM.png

Let’s run a cleverly crafted command that loops through each file in the current directory and renames it (using mv) to translate the whitespace to an underscore:

for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done

Let’s run the ls command again to see what’s changed:

mmontagnino@Marians-MacBook-Pro screenshots % ls
Screen_Shot_2022-12-20_at_10.27.55_PM.png
Screen_Shot_2022-12-20_at_10.32.48_PM.png
Screen_Shot_2022-12-26_at_5.24.48_PM.png
Screen_Shot_2022-12-27_at_12.08.12_AM.png

Wow! We’ve just run a single command and the files are automatically renamed! This is just one example to show the power of CLIs and how much faster tasks can be executed compared to a GUI.

The comeback

The reason there’s been a comeback of the CLI within recent years is because of these many benefits. The GUI can be resource-intensive, tedious when performing repetitive tasks, and sometimes slow.

The CLI, on the other end of the spectrum, is lightweight, scriptable, and fast. The advantages don’t end there. The CLI might even offer commands and parameters that are not available, or are unthinkable, within the GUI. There’s much to be admired and it’s also a little mysterious.

I’m crushing a little on the CLI here! Jokes aside, to be fair to the attractive GUI, it has visual cues that allow the user to be self-guided. The all-too-mysterious CLI, on the other hand, requires help and man pages to understand its available parameters and options.

Though it may appear difficult to understand, once understood, the power of the CLI becomes apparent and inspiring.

 

The philosophy of CLI development

Philosophy plays a major role in the development of computer science. Throughout history, there have been many great contributions to computer science through philosophy, partially because many computer scientists were and are also philosophers. It is no surprise that each OS has its own distinct philosophy.

Windows, for example, hardcodes most of its intelligence within the program or OS, assuming users’ ignorance and limiting their flexibility. Although the barrier to understanding is lower, users interact with the program without understanding how it works.

The developers of UNIX had an opposing philosophy: provide the user with almost limitless possibilities to empower them. Although the learning curve is steep, much more can be developed within an environment that doesn’t shield its users from the complexity of freedom.

There have been many books written about UNIX’s philosophy and implementing it in real life is an art form. I am sure, therefore, many people view coding as a craft. Although there are many other philosophies to review, the focus in this section will be on UNIX’s philosophy.

The legendary designers of the Go programming language, Ken Thompson, Robert Griesemer, and Rob Pike, share a long history with UNIX, and it feels fitting to discuss the philosophy within the context of its creators since Go was built around it.

UNIX’s philosophy advocates for simple and modular designs that are both extensible and composable. The basis is that the relationships between numerous small programs are more powerful than the programs themselves. For example, many UNIX programs handle simple tasks in isolation, but when combined, these simple tools can be orchestrated in a very powerful way.

Checklist for a successful CLI

The following are some principles inspired by this UNIX philosophy that when followed will help create a successful CLI:

  • Building a modular program

Design your CLI with standardization in mind to ensure it can be easily composed with other applications. Specifically utilizing standard in and out, standardized errors, signals, and exit codes helps to build a program that is both modular and easily composable. Composability can be handled simply with pipes and shell scripts, but there are also programming languages that can help piece programs together. Continuous Integration/Continuous Delivery (CI/CD), orchestration, and configuration management tools are often built on top of command-line execution and scripts to automate code integration or deployment or to configure machines. Consider the data output from your program and how easily composable it is. The best options are plain text or JSON when structure is needed.

  • Building for humans first

The first CLI commands were written with the assumption that they’d only be used by other programs. This is no longer the case, and so programs should be built with humans first in mind.

Conversation will be the main method of human-computer interaction. Imagine the natural flow of human conversation and how that concept can be applied to help a user who has misunderstood the program design. In natural language, your program can suggest possible corrections, the current state in a multi-step process, and request confirmation before continuing to do something risky. In the best-case scenario, your user has had a pleasant experience with your CLI, feeling empowered to discover operations and receiving assistance when needed. In the worst-case scenario, your user feels ignored and frustrated with no help in sight. Don’t be that CLI!

Finally, write readable code so other developers can easily maintain your program in the future.

  • Separating interfaces from engines and policies from mechanisms

Decoupling these allows different applications to use the same engine through interfaces or use the same mechanism with different policies.

  • Keeping it simple

Only add complexity when it’s necessary. When complexity does occur, fold it into the data instead of the logic. Where usability is not compromised, use existing patterns.

  • Staying small

Don’t write a big program unless there’s no other way.

  • Being transparent

Be as transparent as possible so users can understand how to use the program and what’s going on. Transparent programs have comprehensive help texts and provide lots of examples allowing users to easily discover the parameters and options they need and have the confidence to execute them. The GUI certainly has a leg up in terms of transparency and visibility; however, we can learn from it and see what can be incorporated to make the CLI easier to learn and use. Users resorting to Google or Stack Overflow is an anti-pattern here.

  • Being robust

Robustness is the result of the former principle: transparency and simplicity. The program should work in a way that the user expects, and when errors occur, explain what is happening clearly with suggestions for resolution. Immediately printing stack traces or not informing the user with a clear and immediate response leaves the user feeling like they are on shaky ground.

  • No surprises

Keep your program intuitive by building on top of a user’s existing knowledge. For example, a logical operator such as + should always mean addition and - should always mean subtraction. Make your program intuitive by staying consistent with pre-existing knowledge and patterns of behavior.

  • Being succinct

Don’t print output unnecessarily and don’t be completely silent, leaving the user to wonder what’s going on. There’s a balance in communication required to say exactly what needs to be said; no more, no less. Too much is a large block of verbose text that forces the user to parse through it to find useful information. Too little is when the command prompt hangs in silence leaving the user to assume a state about the program.

  • Failing noisily

Repair what can be repaired, and when the program fails, fail noisily and as soon as possible. This will prevent incorrect output from corrupting other programs depending on it.

  • Saving your time

Build code to save developers’ time as opposed to the machine’s time, which is relatively cheap these days. Also, write programs that generate programs. It’s much faster and less error-prone for computers to generate code over hand-hacking.

  • Building a prototype first, then optimizing

Sometimes, programmers spend too much time optimizing early on for marginal gains. First, get it working, and then polish it.

  • Building flexible programs

Programs may be used in ways the developers did not intend. Therefore, making the design flexible and open will allow the program to be used in ways unintended.

  • Designing for extensibility

Extend the lifespan of your program by allowing protocols to be extensible.

  • Being a good CLI citizen

Bring empathy into the design and peacefully coexist with the rest of the CLI ecosystem.

The philosophy directly influences the guidelines for creating a CLI. In the next section, you will clearly see the link to satisfy the philosophy tenets discussed, and if anything, following the guidelines will increase the odds of creating a successful CLI.

 

The guidelines

These guidelines have been formulated since the first CLI and have continued to evolve through the many years of developer and user experience. Following these guidelines will increase your chances of CLI success; however, there may be times when you decide to go your own way and follow an anti-pattern. There could be many reasons to choose an unconventional route. Remember that these are just guidelines and there are no hard and fast rules.

For life, and building CLIs, to be fun, we must allow a little chaos and the freedom necessary to be creative.

Name

The name of the CLI holds significant weight as the name may convey symbolic ideas beyond the initial intention. People do not like to think more than necessary, so it’s best to choose a name that is simple, memorable, and easy to pronounce. It’s amazing how many CLI program names have been chosen so arbitrarily without much thought.

There have been studies that support the linguistic Heisenberg principle: labeling a concept changes how people perceive it.

Hence, keep it short and easy to type. Use entirely lowercase variables in the name and only use dashes when absolutely necessary.

Some of my favorite application names are clear in the way that they plainly describe the application’s purpose in a creative manner. For example, Homebrew is a package manager for installing applications on macOS. A brew is a concoction of various ingredients, like a recipe, or in this particular case, a formula, to describe how to install an application. Another great example is imagemagick, a command-line application that lets you read, process, or create images magically! Truly, as Arthur C. Clark writes, “Any sufficiently advanced technology is indistinguishable from magic.” Other internal commands we are familiar with are mkdir, for make directory, rm, for remove, and mv, for move. Their popularity is partially a result of the transparent nature of their names, rendering them nearly unforgettable.

Help and documentation

One of the tenets of the UNIX philosophy is transparency, possible mainly through the help and documentation present within the CLI. For new users of the CLI that are in discovery mode, the help and documentation are one of the first sections they will visit. There are a few guidelines to make the help and documentation more easily accessible to the user.

Help

It is a good practice to display help by default when just the command name is entered or with either the -h or –help flag. When you display the help text, make sure it’s formatted and concise with the most frequently used arguments and flag options at the top. Offer usage examples, and if a user misuses the CLI, the program can guess what the user tried to attempt, providing suggestions and next steps.

Documentation

Provide either man pages or terminal-based or web-based documentation, which can provide additional examples of usage. These types of documentation may be linked from the help page as an extension of the resources for gaining an understanding of how the CLI works.

Support

Oftentimes, users will have suggestions or questions on how to use the CLI. Providing a support path for feedback and questions will allow users to give the CLI designer a new perspective on the usage of their CLI. When collecting analytics, be transparent and don’t collect users’ address, phone, or usage data without consent.

Input

There are several ways a CLI retrieves input, but mainly through arguments, flags, and subcommands. There is a general preference for using flags over arguments and making the default the right thing for most users.

Flags

The guideline for flags is that ideally, there exists a full-length version for all flags. For example, -h has --help. Only use , a single dash, or shorthand notation for commonly used flags and use standard names where there is one.

The following is a list of some standard flags that already exist:

Flag

Usage

-a, --all

All

-d, –debug

Debug

-f, --force

Force

--json

Display JSON output

-h, --help

Help

--no-input

Disable prompt and interactivity

-o, --output

Output file

-p, --port

Port

-q, --quiet

Quiet mode

-u, --user

User

--version

Version

-v

Version or verbose

-d

Verbose

Table 1.1: Standard flags

Arguments

Multiple arguments are fine for simple actions taken on several files. For example, the rm command runs against more than one file. Although, if there exist two or more arguments for different things, you might need to rethink the structure of your command and choose a flag option over an additional argument.

Subcommands

The guidelines for subcommands are that they remain consistent and unambiguous. Be consistent with the structure of subcommands; either noun-verb or verb-noun order works, but noun-verb is much more common. Sometimes, a program offers ambiguous subcommands, such as apt update versus apt upgrade, which causes many, including myself, confusion. Try to avoid this!

Validate the user’s input early, and if it’s invalid, fail early before anything bad happens. Later in this book, we will guide you through using Cobra, a popular and highly recommended command-line parser for Go, to validate user input.

Output

Because CLIs are built for humans and machines, we need to consider that output must be easily consumed by both. I will break down guidelines for both stdout and stderr streams for both humans and machines. Standard output, stdout, is the default file descriptor where a process can write output, and standard error, stderr, is the default file descriptor where a process can write error messages:

  • stdout

A guideline for standard output for humans is to make the responses clear, brief, and comprehensible for the user. Utilize ASCII art, symbols, emojis, and color to improve information density. Finally, consider simple machine-readable output where usability is not impacted.

A guideline for standard output for machines is to extract any extraneous substance from the above response so that it is simply formatted machine-readable text to be piped into another command. When simple machine-readable text is not output by default, utilize the -q flag to suppress non-essential output and --plain to display machine-readable text. Disable color with the --no-color option, by setting the NO_COLOR environment variable, or a custom MYAPP_NO_COLOR environment variable specific to your program.

Additionally, don’t use animations in stdout because it’s not an interactive terminal.

  • stderr

Things can go wrong during the execution of a command, but it doesn’t have to feel like a catastrophic event. Sometimes loud full stack traces are the response to a command failure, and that can make the heart skip a beat. Catch errors and gracefully respond to the user with rewritten error messages that can offer a clear understanding of what happened and suggestions for the next steps. Make sure there’s no irrelevant or noisy output, considering we want it to be easy to understand the error. Also, provide users with additional debug and traceback information and an option to submit bugs. Non-error messages should not go to stderr, and debug and warning messages should go to stdout instead.

Note

As for general guidelines for CLI output, return a zero exit code on success and a non-zero code that the machine can interpret as not just a failure but even a particular type of failure on which to take further action.

Configuration

Users may configure their CLI by using flags, environment variables, and files to determine how specifically to invoke the command and stabilize it across different users and environments:

  • Flags and environment variables

By using flags or environment variables, users may configure how to run a command.

Examples include the following:

  • A specified level of debug output
  • Dry run commands

Alternatively, they can be used to configure between different environments.

Examples include the following:

  • Providing a non-default path to files required for the program to execute
  • Specifying the type of output (text versus JSON)
  • Specifying an HTTP proxy server to route requests through

When using environment variables in configuration, set names appropriately, using a combination of all uppercase text, numbers, and underscores, and take the time to ensure you are not using the name of an already-existing environment variable.

  • XDG Spec

Configure stability across multiple environments by following the XDG Spec (X Desktop Group, freedesktop.org), which specifies the location for base directories where configuration files may be located. This spec is supported by many popular tools, such as Yarn, Emacs, and tmux, to name a few.

Security

Do not store secrets and passwords in environment variables or pass them in via an argument or flag. Instead, store them in a file and use the --password-file argument to allow the secret to be passed in discretely.

Open source community

Once your CLI is complete and ready to be distributed, there are several guidelines to follow. If possible, distribute it within a single binary targeted to a user’s specific platform and architecture. If the user no longer wants or needs your program, make sure it’s easy to uninstall too!

Since you’ll be writing your CLI in Go, it would be great to encourage contributions to your program. You may offer a contribution guideline doc that guides users toward commit syntax, code quality, required tests, and other standards. You could also choose to allow users to extend the CLI by writing plugins that can work with your CLI, break up functionality across more modular components, and increase composability.

Software lifespan and robustness

To ensure your CLI will continue to work well in the future, there are a few guidelines to follow specific to robustness to make sure your program has a long lifespan:

  • Future-proofing

When you make any changes to your CLI, over time, it’s best to make these changes additive, but if not, warn your users of the change. Changing human-readable output is usually fine, but it’s best to keep the machine-readable output stable. Consider how external dependencies may cut short your program’s lifespan and think of ways to make your application stable amidst external dependency failures.

  • Robustness

For a CLI to achieve maximum robustness, the CLI must be designed with full transparency. The program needs to feel responsible for the user; so, show progress if something takes a long time and don’t let the program hang. Make programs timeout when they are taking a long time. When the user inputs a command, validate the usage immediately, giving clear feedback when there’s apparent misuse. When there’s a failure due to some transient reason, exit the program immediately upon failure or interruption. When the program is invoked again, it should pick up immediately where it left off.

  • Empathy

Adding some thoughtful detail to the command-line design will create a pleasant experience for the user. CLIs should be fun to use! Even when things go wrong, with a supportive design, the users can feel encouraged on their pathway to successfully using the CLI. The modern CLI philosophy and guidelines reflect a level of empathy toward humans already and, thank goodness, we’ve come a long way from the initial command-line tools and will continue to do better.

 

Go for CLIs

The very same overarching reasons I suggest engineers learn Go are the very same reasons I suggest using Go to build your CLI, but the very history of modern CLIs, which began in the 1960s with the UNIX shell, invented at Bell Labs by Ken Thompson, co-inventor of Golang, holds much weight. The UNIX philosophy, which inspires our modern CLI philosophy and guidelines, is built into the language, and it’s clear that many benefits have been born out of this way of thinking:

  • Performance, scalability, and power

Golang is quite fast in its compilation and execution. For example, Kubernetes, which is written in Go, has 5 million lines of application code that compile within a couple of minutes. Any other language would take 10 minutes to several hours to compile. Go translates its source code to machine code within its own optimized compiler, allowing easier dependency management. Also, because Golang is still a young language, it’s built for contemporary hardware requirements.

Goroutines are lightweight threads that run concurrently. In my experience programming, I have not seen simplicity and multi-threading go hand in hand, but Golang achieves this extremely well. This feature won my heart.

The performance and scalability of Go are an obvious draw to the cloud computing community. Many CLIs for cloud computing were written in Go, Docker and Kubernetes included. Any application with a growing user base or a high number of traffic requests needs to consider Golang. Companies such as Uber and Comcast have chosen Go for this reason as well.

  • Simplification of development

Golang felt easier to learn than any other language I’ve ever encountered. The language supports a clean, simple, and fast environment, which is impressive, considering the powerful tools that Go has created. Golang also has many tools that allow the speed and accuracy of development, including formatting tools, testing frameworks, a great linter, and tools to perform static analysis.

  • Versatility

Go makes cross-compilation so easy. You can build your application for many different OSs and architectures, increasing accessibility to your CLI. Although executing within different environments, if properly configured, it will work similarly. This will ease users’ minds. Later on in this book, we will discuss how to create binaries for different platforms.

  • Growing your skillset

Golang is among the most popular languages to learn. Given its many apparent benefits, more start-ups and enterprises are choosing Golang and the demand for Golang developers is growing.

  • Community

If you choose Go, you’ll be a part of a community of enthusiastic open source developers, willing to partake in the evolutionary journey of a young programming language.

For beginners who are building a CLI in Go for the first time, the next chapters ahead show how clear it is. Golang is an excellent choice for building a CLI, and when there’s a need for scalability, performance, and cross compilation, the choice will play in your favor.

 

Summary

In this chapter, you learned about the scientific discoveries and inventions that led to the creation of the CLI and the remnants of the past that still exist within the terminal today.

Besides a detailed breakdown of the CLI into its parts, this chapter also discussed what a CLI is, overall, and what it is used for. The co-creator of UNIX and Golang, Ken Thompson, influences the philosophy around CLIs and programming in general. This philosophy has been influenced by human and computer interaction over the decades. As with anything with a long history, some ancestral baggage has followed. We learned that in the past, CLIs were primarily written for computers, and today are primarily written for humans. A new element to the UNIX philosophy had to be added: empathy as a cultural norm.

This chapter dug into the guidelines that ultimately embody the UNIX philosophy and why Golang is the best language to implement such a design.

In Chapter 2, Structuring Go Code for CLI Applications, we will discuss the first step of project creation: folder structure.

 

Questions

  1. What is the TTY on a Linux machine and what is the history behind this command?
  2. Which of the core elements of UNIX’s philosophy do you resonate with the most? Why?
  3. Who are the co-creators of Golang and what is their relationship to the UNIX OS?
  4. Can you still visit BBSs today and play some of the old text-based games of the past?
  5. Which of the CLI guidelines feels second nature to you and which guidelines would require extra effort?
 

Answers

  1. TTY is a command in UNIX and Linux to display the name of the terminal connected to standard input. TTY is derived from the word teletypewriter, which was the default form of interacting with large mini and mainframe computers.
  2. This answer is subjective. However, I like the element of building a prototype first and optimizing second. I prefer the process of building a simple proof of concept that can be used as inspiration. Optimization and refinement can always come later.
  3. Golang was created by Robert Griesemer, Rob Pike, and Ken Thompson. Ken Thompson also created the UNIX OS and Rob Pike was a member of the UNIX team.
  4. You can still visit BBSs today by downloading a telnet client, for example, CGTerm, and connect to over 1,000 different BBSs still running today. View the list at https://www.telnetbbsguide.com/.
  5. This answer is subjective. However, I find it second nature to put effort into building constructive help text. Conversely, I think it takes extra effort to write out complete and up-to-date documentation.
 

Further reading

  • PhiloComp.net (https://philocomp.net/) is an educational website for both computer scientists and philosophers to learn the links between the disciplines, expanding their view of the other and of themselves
  • Command Line Interface Guidelines (https://clig.dev) is an excellent resource with plenty of examples of creating CLI applications that adhere strongly to the UNIX philosophy
About the Author
  • Marian Montagnino

    Marian Montagnino is a Senior Software Engineer at Netflix with over 20 years of experience. Since the early nineties, when her family first got a home computer, she has been using the terminal and command line applications to navigate through text based systems. In 1995, she held her first job as a SysOp, or system operator, for Real of Mirage BBS in Fair Lawn, NJ. Her early years discovering technology inspired her to continue learning about computers. She received her Dual Computer Science and Mathematics of Operations Research BSc from Rensselaer Polytechnic Institute and her Applied Mathematics MSc from Stevens Institute of Technology.

    Browse publications by this author
Building Modern CLI Applications in Go
Unlock this book and the full library FREE for 7 days
Start now