37,99 €
Evolve the humble CLI using Go and unleash the next generation of powerful, flexible, and empathy-driven interfaces
Purchase of the print or Kindle book includes a free PDF eBook
Key Features
Book Description
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.
What you will learn
Who this book is for
This book is for beginner- and intermediate-level Golang developers who take an interest in developing CLIs and enjoy learning by doing. You'll need an understanding of basic Golang programming concepts, but will require no prior knowledge of CLI design and development. This book helps you join a community of CLI developers and distribute within the popular Homebrew package management tool.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 444
Veröffentlichungsjahr: 2023
Develop next-level CLIs to improve user experience, increase platform usage, and maximize production
Marian Montagnino
BIRMINGHAM—MUMBAI
Copyright © 2023 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Group Product Manager: Gebin George
Publishing Product Manager: Pooja Yadav
Senior Editor: Nisha Cleetus
Technical Editor: Pradeep Sahu
Copy Editor: Safis Editing
Project Coordinator: Manisha Singh
Proofreader: Safis Editing
Indexer: Hemangini Bari
Production Designer: Joshua Misquitta
Business Development Executive: Kriti Sharma
Developer Relations Marketing Executives: Rayyan Khan & Sonia Chauhan
Production reference: 2080323
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-80461-165-4
www.packtpub.com
Above all, I would like to express my gratitude to the Divine Intelligence, the source of all creation, for all the blessings and opportunities that helped me bring this book to life.
To my dear old dad, Dr. Joseph Montagnino, who always cheered me on in all things math and tech. Without you, I would not be the fearless learning machine I am today.
To my dearest mother, Lilia Banogon Montagnino, thank you for always seeing the potential in me and for being my guiding light throughout life. Your unwavering belief in me has given me the strength to face any challenge and pursue my dreams fearlessly.
To my dear sister, Lillian, your unwavering support and encouragement in self-discovery have allowed me to pursue my passion and find my true creative self.
To my nieces, Carine and Maple, and nephew, Cayden, thank you for the joy and playfulness you bring to my life.
To Julia and her late father, Marc Howe - you and the team at Cyber Warrior, Inc were my tech-savvy guild of wizards to guide and inspire me, and for that, I am forever grateful. Your mentorship and friendship paved the way for me, and I’ll never forget it.
And to all my cherished friends and family - you all keep me grounded, laughing, and full of love. Thank you for being my support system and for making life so darn wonderful.
– Marian Montagnino
On November 10, 2009, a historical announcement was made by Robert Griesemer, Rob Pike, Ken Thompson, Ian Taylor, Russ Cox, Jini Kim, and Adam Langley. They announced to the world a new experimental language called Go. It was on this day that the Go programming language was open sourced and available for the world to use. As we wind the clock forward 12 years to 2023, the language is currently ranked as the 12th most popular language in the world on the Tiobe index.
In 2016, the Go team released the results of their annual survey for the first time. One question in the survey asked people what they were writing in Go. Here are the top seven results of that question:
2,247 (63%): A runnable/interactive program (or CLI)2,174 (60%): API/RPC services (returning non-HTML)1,886 (52%): Web services (returning HTML)1,583 (44%): Agents and daemons (e.g, monitoring)1,417 (39%): Libraries or frameworks1,209 (34%): Data processing (pipelines and aggregation)1,120 (31%): Automation/scripts (e.g, deployment and configuration management)At the time in 2016, CLI tooling was the number one use of Go. 8 years later in the 2022 survey, API/RPC services top the list at 73%, but a close second is CLI tooling at 60%. What might be more exciting is if you search the web for the best languages to use for building command-line tools, Go will always be at the top of any list.
If you have picked up this book because you need to write a command-line tool and you’re thinking about using Go, or you’ve already chosen Go but need help on how to write the best CLI possible, you’ve picked up the right book. Marian is a seasoned software engineer with many years of experience writing CLI tooling for the companies and projects she has worked on. This book is what she wished she had when she was asked to write her first command-line tool.
I’m certain that you will learn what you need from this book and that the book will help jumpstart your knowledge into writing runnable and interactive programs in Go. You can feel confident that what Marian is teaching you will be idiomatic Go, following the best practices, design philosophies, and guidelines known today for CLI development and useability.
William Kennedy
Managing partner at Ardan Labs
Go trainer, writer, and speaker
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.
To the exceptional members of the Go community, particularly Bill Kennedy, Natalie Pistunovich, Mat Ryer, Steven Francia, and Erik St .Martin, your creativity and innovation continue to inspire me towards greatness.
Finally, thank you to the wonderful team at Packt for their help and support throughout the process; I couldn’t have done it without you!
Wisnu Anggoro is a backend engineer with more than 10 years of experience in developing and maintaining distributed systems. He has expertise in Golang (Go Programming Language) and microservices architecture to solve complex software problems by implementing innovative solutions.
Tushar Sadhwani is a long-term Python and Go developer, open source contributor, author, and speaker. He is currently a Language Engineer at DeepSource, where he works on building linters and code analysis tools for Python. He has been an advocate of static type checking for over three years, and has been contributing to static code analysis tools over the past two.
This part covers the Command-Line Interface (CLI) and its resurgence in popularity. The history, anatomy, and design principles of the CLI are discussed, with a focus on UNIX’s philosophy and the benefits of using Go to build a CLI. The guide offers a step-by-step approach to building a new application, including code structure, domain-driven design, and an example audio metadata CLI application. Hands-on learning is encouraged with the example audio metadata CLI application, and popular frameworks, such as Cobra and Viper, are explored to speed up the development process. Overall, this part provides a comprehensive overview of the CLI and its practical applications in modern programming, offering valuable guidance to developers looking to build efficient and effective CLI applications.
This part has the following chapters:
Chapter 1, Understanding CLI StandardsChapter 2, Structuring Go Code for CLI ApplicationsChapter 3, Building an Audio Metadata CLIChapter 4, Popular Frameworks for Building CLIsThe 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 lineThe philosophy of CLI developmentModern CLI guidelinesGo for CLIsThe 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.
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.
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.
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 transcriptIn 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.
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.
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.
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.
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.pngYou 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.pngNote
Although whitespace is the most widely used delimiter, it is not universal.
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.
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}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.
There are two main types of CLIs:
OS CLIsApplication CLIsOS 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.
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 wayInteractive command-line sessions: They are launched after the application as an independent and text-alternative method of controlInter-process communication: This allows users to stream or pipe data from the output of one program into anotherLet’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.
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:
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
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
Finally, manually replace each of the whitespaces with an underscore.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.
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.pngLet’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 ' ' '_'` ; doneLet’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.pngWow! 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 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.
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.
The following are some principles inspired by this UNIX philosophy that when followed will help create a successful CLI:
Building a modular programDesign 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 firstThe 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 mechanismsDecoupling these allows different applications to use the same engine through interfaces or use the same mechanism with different policies.
Keeping it simpleOnly 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 smallDon’t write a big program unless there’s no other way.
Being transparentBe 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 robustRobustness 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 surprisesKeep 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 succinctDon’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 noisilyRepair 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 timeBuild 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 optimizingSometimes, programmers spend too much time optimizing early on for marginal gains. First, get it working, and then polish it.
Building flexible programsPrograms 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 extensibilityExtend the lifespan of your program by allowing protocols to be extensible.
Being a good CLI citizenBring 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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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:
stdoutA 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.
