How to design a CLI
Vercel’s a got a great system for deploying serverless JS web apps. It Just Works(TM). Vercel’s CLI however…is a learning example. We’ll go over some of their interesting and noteworthy design choices, and then, describe what other option we could take.
Write by default to stderr
People use CLIs because they’re cheap on bandwidth, RAM, CPU, and don’t have images. It certainly has nothing to do with UNIX’s rich set of tools and composability.
$ vercel ls | grep https
Vercel CLI 28.4.10
> Deployments for [REDACTED] under [REDACTED] [366ms]
> To list deployments for a project, run `vercel ls [project]`.
Age Deployment Status Duration
5m https://[REDACTED].vercel.app ● Ready 17s
57m https://[REDACTED].vercel.app ● Ready 17s
But Only do it for some part of one help message
$ vercel inspect --help | grep ls
Vercel CLI 28.4.10
$
Being inconsistent keeps us on our toes to ensure our skills stay sharp.
Instead: Write to stdout. Except you know, errors
That way if we want to filter the output, we can. you know. just grep it.
$ vercel ls | grep https
5m https://[REDACTED].vercel.app ● Ready 17s
57m https://[REDACTED].vercel.app ● Ready 17s
Include lots of header information
It’s important every time we run the command that we know which version. It’s a huge problem if we run 27.3.8 instead of 28.4.10. We also need to be reminded ever time that we can use vercel ls [project]
lest we forget
Instead: Only include what We need
$ vercel ls
Age Deployment Status Duration
5m https://[REDACTED].vercel.app ● Ready 17s
57m https://[REDACTED].vercel.app ● Ready 17s
Here, we just get the data and a header row, like ps. If we want more, we can use a verbosity level. The version can be a version flag It’s not super important where we draw the lines, as long as we invoke the Rule of Silence in the flagless case.
$ vercel ls -V
Vercel CLI 28.4.10
$ vercel ls -v
> Deployments for [REDACTED] under [REDACTED] [366ms]
> To list deployments for a project, run `vercel ls [project]`.
Age Deployment Status Duration
5m https://[REDACTED].vercel.app ● Ready 17s
57m https://[REDACTED].vercel.app ● Ready 17s
Use low precision relative timestamps
Age Deployment Status Duration
5m https://[REDACTED].vercel.app ● Ready 17s
1d https://[REDACTED].vercel.app ● Ready 16s
1d https://[REDACTED].vercel.app ● Ready 17s
Nobody needs to know exactly when it was created, some number of minutes or days ago is good enough. That would be silly. Nobody ever wants to query when they deployed using this tool. 1 day ago’s all we need. Who cares if it was morning or night, it’s not like I’m trying to make a deploy frequency graph.
Instead: Absolute ISO8601 second precision timestamps
$ vercel ls
DateTime Deployment Status Duration
2023-07-06T23:38:37Z https://[REDACTED].vercel.app ● Ready 17s
2023-07-05T23:38:37Z https://[REDACTED].vercel.app ● Ready 16s
2023-07-05T22:38:37Z https://[REDACTED].vercel.app ● Ready 16s
Now we can easily create a frequency plot of deploys by day:
vercel ls | sed 1d | cut -d ' ' -f 1 | jq -R '.' | jq -s 'group_by(.[:10]) | map({key: .[0][:10], value: length}) | from_entries' | plot-json > by_date.png
Or by minute, or time of day, whatever we want because we have the precise data and it’s in an easily parsable format.
Use multibyte unicode characters
●
What a spiffy looking dot, so much better than o, x, or 0. It’s so edgy it confuses crufty software like unix. Is it 1 byte, or 3?? It looks like one, but wc thinks it’s 3 and cut…just gets weird.
$ echo a | wc
1 1 2
$ echo ● | wc
1 1 4
$ echo abcd | cut -c 1-3
abc
$ echo ab●cd | cut -c 1-3
ab
Also it’s a super secret exclusive character that ● is not on a keyboard. For this post I had to copy paste it whenever I wanted to use it.
Instead: Nothing
Don’t use anything at all. It adds nothing functional. If you really want something, use 0, x, or o. If you must use something prettier than ASCII 0, x, and o, realize for aesthetics, you’re losing the ability to write programs against the data. A big no-no in the fast coding world.
Conclusion
As we can see Vercel made some choices. All of them lead to fast coding and are definitely absolutely optimal. We’ve presented a few alternatives just to appreciate the brillaince of why they’re the fast coder choices.