Build CLI tools for common tasks

2021-01-13

I frequently build command-line (CLI) tools to perform common tasks. These tools not only help me to do my job more effectively, but also have other compounding effects on productivity.

Here’s an example. I find myself often needing to fetch information about particular entities during my day-to-day work. Sometimes it’s to investigate an issue, or simply to test some feature I’m developing. Simple fetches are often the first thing I write tooling for:

$ listingclient get <ID>
{"title": "Macbook Pro", "description": "", "price": 1200.00, ...}

Why build tooling?

How about a web interface?

At Carousell we have an internal web platform. However it’s not built in a way that makes it easy for backend engineers to contribute to, which means its feature set is often lagging behind what the engineers need. The platform often only exposes high-level information, since the primary user demographic are non-tech folks. Unless you’re fortunate enough to work somewhere that has a robust internal platform you can easily contribute to, it’s far easier to spin up some CLI tooling.

In addition, here are some reasons why I generally prefer working with CLI tools:

Tips

This is a good reference for CLI guidelines.

Here are some of my personal ones:

Examples

My most common use-case is to get information about various entities.

listingclient get <ID>
categoryclient get <ID>

We also have commands that implement CRUD operations. Here’s a set of commands (tweaked for brevity) we have for performing bulk jobs.

listingclient bulkjob get --limit 5               // get the 5 most recent jobs
listingclient bulkjob create <...args>            // create a new job
listingclient bulkjob [pause|unpause|cancel] <ID> // manage the job state

As mentioned before, I subscribe to the Unix philosophy of building tools that do one thing and do it well. I like to build in such a way that workflows can be composed on top of the commands. For instance, if I wanted to monitor the progress of a particular job, I could simply do the following.

watch 'listingclient bulkjob get <ID> | jq'

Here’s another example of composing a workflow. Let’s say I have some entity that I’d like to edit. I could very easily compose a script that (1) gets the entity, (2) opens it in an editor for editing, and (3) updates the entity.

#!/bin/bash
ID=$i
fooclient foo get $ID | jq '.' > /tmp/foo_$ID.json
vim /tmp/foo_$ID.json
fooclient foo update --file /tmp/foo_$ID.json --id $ID

Hopefully this post has given you some inspiration!