I spent the last month working on a personal project, doclt. I was inspired to build this after cleaning up some code on my side project nycurl, which uses a package called cli-table2 that formats data into nicely displayed tables for display in any terminal or command line. I thought it would be cool to use it to display Digital Ocean resources since I use Digital Ocean a lot for hosting my personal projects. This post will mostly describe my process building this project as well as giving general tips on building a CLI.
To build any command line interface, one needs a good command line argument parser as a backbone on which to build functionality. Two very good ones are commander and yargs.
When I started building this project, I decided to use node.js so that I could distribute this package on npm. I was using the commander package to do my command line argument parsing. Although robust, commander wasn’t designed for the complex tree of commands that I had in mind for this project.
Aside from that, npm also gave me a few problems when I was looking for a good command line argument parser. Generally, I like npm. It’s a great place for cool packages and projects. No matter how awesome open source code is though, it will always be a cluster****. I ran into commander, commander-plus, and commander-plus-plus.
Guess which one is newest and most updated? That’s right, commander-plus.
Now look at their documentation.
??????
Apparently, commander-plus is a fork of commander, but the maintainers didn’t bother updating the documentation.
It was this point that I burned down the project and ran rm -rf on the project directory. Then I moved on to the yargs command line argument parser and rewrote the entire project. Switching to yargs was almost as glorious as switching from Notepad++ to Emacs. Aside from being extraordinarily well documented, yargs allowed me to organize my project into a beautiful tree of commands.
My goal with this project was to build a command line interface so that I could provision and manage Digital Ocean droplets, volumes, and other resources from the command line. Digital Ocean’s v2 documentation is fantastic and easy to read, and there already existed a node.js wrapper for it. I used the digitalocean package to manage calls to the Digital Ocean API. There were some minor bugs with the package, so I ended up sending a few pull requests to the repository as well. That ended up being a pretty cool refresher on how to open source.
I envisioned a UI that looked something like this:
With this in mind, I mostly followed the Digital Ocean API documentation in designing the commands. In the end, the command tree looked something like this:
Originally, this project was called the Digital Ocean Command Line Interface (docli), but during publishing time, I found out that package name was taken on npmjs. Since “doctl” wasn’t taken, I renamed the project to the Digital Ocean Command Line Tool.
I don’t know why, but I always measure the legitimacy of a project by the badges on their README, so of course I have to sprinkly a few on my own, courtesy of shields.io.
Anyway, tips for creating a CLI:
- Separate out all the functions of your CLI into small, compartmentalized commands. It should be obvious to the user how your CLI is used.
- For more complex CLI applications, use git-style subcommands to organize the commands. You can see this in doctl in the picture of the command tree above.
- Each command should be relatively self-documenting. It should be obvious how a command works. This is nuanced however, and may depend on your application.
- Spend a lot of time designing usage information and man-pages. Make sure its accessible via a help flag or help command. Keep your command descriptions short and concise.
bower is a fine example of well designed command documentation.
- Optionally, you can also include example usage of commands like most Unix style man-pages.
I’m obsessed with doing stuff from the command line for some reason. Leave a comment if you’ve created any cool command line applications. That’s all I have for now. If you enjoyed reading this, please hit that ❤ down below :)
Follow me on Twitter: @omgimanerd