CLIコマンド設計入門

# はじめに

こんにちは、AWSインフラエンジニアのかふぃです。
最近Goを学んでいて、担当している案件の業務効率化のためにCLIアプリを作ろうと思い、CLIコマンドの設計哲学について勉強を始めました。
学んだことをまとめたので、ご参考になれば幸いです。

# 目次
- [参考資料](#参考資料)
- [UNIX哲学](#unix哲学)
- [CLIコマンドの基本](#cliコマンドの基本)
  - [コマンド名の決め方](#コマンド名の決め方)
  - [コマンドは動詞、引数は名詞](#コマンドは動詞引数は名詞)
  - [オプションは副詞](#オプションは副詞)
- [CLIアプリケーション](#cliアプリケーション)
  - [CLIアプリの特徴](#cliアプリの特徴)
  - [CLIアプリは「呼びかけ+動詞+名詞」の形](#cliアプリは呼びかけ動詞名詞の形)
  - [オプションのルールも変わらない](#オプションのルールも変わらない)
- [まとめ](#まとめ)

# 参考資料
以下の資料を参照しました。特に、Building an Awesome CLI App in Goは端的でわかりやすかったのでおすすめです。
#### [Building an Awesome CLI App in Go](https://spf13.com/presentation/building-an-awesome-cli-app-in-go-oscon/)
>導入文訳：ユーザーフレンドリーなコマンドラインインターフェイスとコマンドスイートを作成するために必要なテクニック、原則、ライブラリの概要を説明してから、独自のアプリの構築手順を説明します。その過程で、コマンドの設計と構築方法から、フラグ、構成ファイル、リモート構成システムの操作と解析、環境変数と 12 ファクター アプリの操作方法まで、あらゆることをカバーします。ワークショップの最後には、Go の実用的な知識と、機能する独自の CLI アプリを習得できます。

#### [CLI Style Guide, Heroku](https://devcenter.heroku.com/articles/cli-style-guide)
>導入文訳：Heroku CLI プラグインは、人間にとって読みやすく使いやすいことを主な目的として、ユーザーに満足してもらえる明確なユーザー エクスペリエンスを提供すると同時に、上級ユーザーや出力形式をサポートする必要があります。この記事では、快適な CLI プラグインを設計するための明確な方向性を示します。




# UNIX哲学
2003年に出版されたThe Art of UNIX ProgrammingというEric S. Raymondさんの書籍で、KISS(Keep it Simple, Stupid)の原則としてまとめられました。以下は[Building an Awesome CLI App in Go](https://spf13.com/presentation/building-an-awesome-cli-app-in-go-oscon/)で抜粋して紹介されていたものです。

- **Simple（シンプル）**
- **Clear（明確）**
- **Composable（組み合わせ可能）**
- **Extensible（拡張可能）**
- **Modular（モジュール性）**
- **Small（小さく）**

# CLIコマンドの基本
## コマンド名の決め方
| コマンド（省略形） | 意味（原形） |
|---------|------|
| `ls`    | list（一覧） |
| `cp`    | copy（コピー） |
| `rm`    | remove（削除） |

短く、しかし意味がわかるようにします。

## コマンドは動詞、引数は名詞
```bash
ls /home
# → List the home directory
#   動詞　      名詞
```
`ls`が動詞、`/home`が名詞。
```bash
cp file.txt backup.txt
# → Copy this file to here
#   動詞    名詞　　　 名詞
```

動詞 `cp` に対して、`file.txt`（元ファイル）と `backup.txt`（新しいファイル名）は名詞。

---

## オプションは副詞
フラグともいう。動詞の振る舞いを変える/調整する働きを持つ。動詞に対する副詞の働き。
```bash
rm -f file.txt
rm --force file.txt
# → Remove Forcefully file.txt
#    動詞     副詞       名詞
```
`-f` と `--force` は同じ意味で、動詞 `rm` の振る舞いを変える“副詞”的な存在。
※英語としてはForcefully remove file.txtですが、便宜上コマンドの順番通りにしています。

```bash
ls --color /home/user
# → List colorfully the home directory
#   動詞    副詞           名詞
```

### 副詞が影響を与えるもの
- manner：方法
- place：場所
- time：時間
- frequency：頻度
- degree：程度
- level of certainty：確実性
- etc.

簡単にいうと、
- How?：どのくらい？
- In what way?：どうやって？
- When?：いつ？
- Where?：どこで？
- To what extent?：どのくらいまで？

これらを意識して、動詞単位で分けるのか、動詞は固定で副詞で調整するのかを考えて設計する。

### `--width=40` のような指定は前置詞+目的語で副詞の役割

```bash
ls --width=40
# → List this directory with a width of 40 columns
```
「前置詞＋その目的語」で構成され、副詞として振る舞う。

# CLIアプリケーション

 `ls` や `cp` などのOSの組み込みコマンドに対するCLIアプリケーション。
例：
- `httpd`
- `vi`
- `emacs`
- `git`

## CLIアプリの特徴
- アプリケーションを起動する。
- １つ以上のことができる（lsなどのような１つのちょっとしたことしかしないのではなく、より多くのことをする）。
- コマンド（サブコマンドと呼ばれる）の集合体である。
- サブコマンドにもこれまでのルールが同様に適用される。

CLIアプリにはサブコマンドというのがある。これは、さっきのlsとかcpと同じ立ち位置。
```bash
svn add
brew install
npm search
apt upgrade
git clone
# アプリ名 動詞(コマンド)
```

先ほどまでのlsとかcpはosの組み込みコマンドで、これをCLIアプリと同様に扱うなら下記のようなものだったと考えてもいいかもです。
```bash
oscli ls
oscli cp [file] [newfile]
# アプリ名 動詞(コマンド)
```

## CLIアプリは「呼びかけ+動詞+名詞」の形
```bash
brew install hugo
# → Brew, install hugo.
#   呼びかけ 動詞  名詞
```
「Brew、hugoをインストールしてください」という感じ。

## オプションのルールも変わらない
```bash
brew fetch -v hugo
# → Brew, fetch verbosely hugo
#   呼びかけ 動詞   副詞   名詞
```

サブコマンドやオプションの使い方にも、これまでの設計ルールがそのまま適用される。


# まとめ

CLIは、**動詞（コマンド）＋副詞（フラグ）＋名詞（引数）** という構造で成り立っており、この設計思想に従うことで、一貫性を持ったCLIコマンドを設計することができそうです。

簡単にCLIコマンドの構成要素をまとめました。
- 小さくても意味のある動詞（コマンド）
- 必要に応じて動作を変える副詞（フラグ）
- 操作対象となる名詞（引数）

GoでCLIアプリ作ったらまたブログにしようと思います。
読んでいただきありがとうございました！