CLI スタイルガイド
最終更新日 2024年04月25日(木)
Heroku CLI プラグインでは、主にユーザーの読みやすさと操作性を目的にした、明確なユーザーエクスペリエンスが提供されます。これにより、ユーザーが快適に操作できると同時に、上級ユーザーや高度な出力形式もサポートされます。この記事では、快適な CLI プラグインを設計するための明確な方向性を示します。
ミッションステートメント
Heroku CLI はマシン用である前に、人間のために存在します。CLI プラグインを開発する人はだれでも、一番の目標を常に操作性に置くべきです。ユーザーが新しいコマンドの操作方法を簡単に習得できるするように、入力と出力はコマンド間で一貫している必要があります。
コマンドの名前付け
プラグインは、トピックとコマンドで構成されます。コマンド heroku apps:create
の場合は、apps
がトピックであり、create
がコマンドです。
一般に、トピックは複数の名詞であり、コマンドは動詞です。
理想的には、プラグインは 1 つのトピックをエクスポートするか、または既存のトピックにコマンドを追加するべきです。
トピックとコマンドの名前は常に、スペース、ハイフン、アンダースコアなどの単語区切り記号を含まない 1 つの小文字の単語であるべきです。ただし、コロンはサブコマンドを定義するための方法であるため許可されます (heroku apps:favorites:add
など)。複数の単語を避けるためのはっきりした方法がない場合は、kebab-case で区切ります (heroku pg:credentials:repair-default
など)。
トピックは一般に名詞であるため、トピックのルートコマンドは通常、これらの名詞を一覧表示します。そのため、heroku config
の場合は、アプリのすべての環境設定を一覧表示します。heroku config:list
などの *:list
コマンドは決して作成しないでください。
説明
トピックとコマンドの説明は、すべてのトピックとコマンドで提供するべきです。これらは 80 文字幅の画面に収まり、小文字で始まるべきであり、ピリオドで終わるべきではありません。
入力
コマンドへの入力は通常、フラグと引数によって提供されます。ファイルまたは情報をストリーム入力することが有効な場合は、stdin も使用できます (heroku run
での場合など)。
フラグ
フラグは引数より推奨されます。必要な入力は少し増えますが、CLI の使用をより明確にします。たとえば、作成されるアプリの引数を受け付けるために使用される heroku fork
や、フォークされるソースアプリを指定するための標準の --app
フラグなどがあります。
そこで、機能する heroku fork
を使用すると、次のようになります。
$ heroku fork destapp -a sourceapp
これは、どのアプリからフォークし、どのアプリにフォークするかが明確でないため、ユーザーにとっては紛らわしい方法です。必須フラグに切り替えることによって、代わりに次の形式の入力が期待されます。
$ heroku fork --from sourceapp --to destapp
これにより、ユーザーはフラグを任意の順序で指定することもできるようになり、コマンドを正しく実行しているという自信が得られます。また、より適切なエラーメッセージを表示することも可能になります。
すべてのフラグで説明が提供されていること、説明が小文字で表され、かつ (狭い画面に収まるように) 簡潔であること、他のフラグの説明と適合するようにピリオドで終わっていないことを確認してください。
フラグでは、引数よりはるかに優れた方法でオートコンプリートを提供できます。これは、ユーザーが次のように入力したとき、
$ heroku info --app <tab><tab>
次に入力するものはアプリ名であり、別のフラグやその他の種類の引数ではないことが疑いの余地なくわかるためです。
フラグの使用方法についての詳細は、「CLI プラグインの開発」を参照してください。
引数
引数は、コマンドへの入力を指定するための基本的な方法です。一般にはフラグが推奨されますが、引数が 1 つしかない場合や、引数が明らかで、かつ明らかな順序になっている場合、フラグは不必要です。
heroku access:add
の場合、アクセス権を付与するユーザーは引数で指定できますが、権限は必須フラグで指定されます。
$ heroku access:add user@example.com --privileges deploy
これが引数のみで実行されたとしたら、権限がメールの前または後のどちらになるかが不明確になります。代わりに必須フラグを使用すると、ユーザーは、それをどちらの方法でも指定できます。
プロンプト入力
欠落している入力のためのプロンプト入力は、CLI で複雑なオプションを表示するための優れた方法です。たとえば、heroku keys:add
は、アップロードに使用できる SSH キーが複数ある場合、次の内容を表示します。
$ heroku keys:add
heroku keys:add
? Which SSH key would you like to upload? (Use arrow keys)
❯ /Users/jdickey/.ssh/id_legacy.pub
/Users/jdickey/.ssh/id_personal.pub
/Users/jdickey/.ssh/id_rsa.pub
このようなプロンプトを表示するには inquirer を使用します。
ただし、コマンドを完了するためにプロンプト入力が必要な場合は、ユーザーがコマンドをスクリプト化できないことになります。プロンプトをスキップするために引数またはフラグを常に指定できることを確認してください。この場合、heroku keys:add
は、プロンプトをスキップするために SSH キーへのパスの引数を受け取ることができます。
出力
一般に、CLI は、データを表示する出力コマンドと、アクションを実行するアクションコマンドの 2 種類のコマンドを提供します。
出力コマンド
出力コマンドは単純に、ユーザーにデータを表示するコマンドです。これには多くの形式がありますが、最も単純なものは this.log()
による stdout への単なる出力です。
this.log('output this message to the user')
// output this message to the user
一般的な出力ヘルパーについては、cli-ux を参照してください。
アクションコマンド
アクションコマンドは、何らかのリモートタスクを実行するコマンドです。たとえば、heroku maintenance:on
はアプリをメンテナンスモードにします。
$ heroku maintenance:on --app myapp
Enabling maintenance mode for ⬢ myapp... done
この出力を表示するには、cli-ux の cli.action() を使用します。このコンポーネントを使用すると、API からの警告やエラーが正しく表示され、スピナーが tty であるときはそれが正しく表示され、tty でないときは代替出力が使用され、さらにスピナーが適切なプラットフォーム上で動作することが保証されます。
アクションは、実行中のタスクに関する帯域外の情報であるため、stderr に表示されます。
色
ユーザーがコマンド出力をすばやく読み取れるように、コマンドでは色の使用が推奨されます。アプリや環境設定などの CLI の一部の名詞には、可能な場合は使用するべき標準色があります。
import color from '@heroku-cli/color'
this.log(`this is an app: ${color.app(myapp.name)}`)
this.log(`this is a config var: ${color.configVar(myapp.name)}`)
標準色を使用できない場合は、color
を使用して他の色を表示することもできます。
推奨される色は、マゼンタ、シアン、青色、緑色、灰色です。色の使用を多様化するために、.dim
、.bright
、.underline
、背景色も使用できることを忘れないでください。
色には注意が必要です。同じ場所にある対比色が多すぎると、すぐに、それらがユーザーの注意を引こうと競い始めます。数個の色を使用し、場合によって既存の色を薄くしたり濃くしたりするだけでたいてい、十分な対比が得られます。
黄色や赤色も使用できますが、これらは通常、エラーや警告メッセージのために残されることに注意してください。
色は、ユーザーが --no-color
を追加するか、COLOR=false
を設定することによって無効にできます。または、出力が tty でないときは無効になります。
人間に解読可能な出力とマシンで解読可能な出力の比較
簡潔な、マシンで解読可能な出力形式も有効ですが、読みやすい CLI 出力作成の妨げにするべきではありません。ユーザーが CLI を簡単に解析してスクリプト化できるようにするために役立つ場合、必要に応じて、コマンドは --json
フラグか --terse
フラグ、またはその両方を提供するべきです。
コマンドの将来のリリースでは、コマンドは一般提供の後、その入力や stdout を (できるだけ) 現在のスクリプトを失敗させるような方法では変更しないことに注意する必要があります。これは一般に、追加情報は問題ないが、既存の出力の変更は問題があることを示します。
grep で解析可能
人間に解読可能な出力は grep でも解析可能ですが、必ずしも awk で解析可能ではありません。たとえば、heroku regions
を見てみましょう。ある地点での heroku regions
が次のような出力を表示しました。
$ heroku regions
Common Runtime
==============
eu Europe
us United States
Private Spaces
==============
frankfurt Frankfurt, Germany
london London, United Kingdom
montreal Montreal, Canada
Mumbai Mumbai, India
oregon Oregon, United States
singapore Singapore
sydney Sydney, Australia
tokyo Tokyo, Japan
virginia Virginia, United States
ここには、使用可能なリージョンに関するすべての情報が表示されていますが、grep
を使用してデータをフィルター処理することはできません。これらの情報を表示するためのより優れた方法を次に示します。
$ heroku regions
ID Location Runtime
───────── ─────────────────────── ──────────────
eu Europe Common Runtime
us United States Common Runtime
frankfurt Frankfurt, Germany Private Spaces
london London, United Kingdom Private Spaces
montreal Montreal, Canada Private Spaces
Mumbai Mumbai, India Private Spaces
oregon Oregon, United States Private Spaces
singapore Singapore Private Spaces
sydney Sydney, Australia Private Spaces
tokyo Tokyo, Japan Private Spaces
virginia Virginia, United States Private Spaces
これらのテーブルは、heroku-cli-util の cli.table() を使用して生成します。
これで、grep を使用して Common Runtime 領域だけをフィルター処理できるようになりました。
$ heroku regions | grep "Common Runtime"
eu Europe Common Runtime
us United States Common Runtime
または、東京だけを表示する場合は、次のようにします。
$ heroku regions | grep tokyo
tokyo Tokyo, Japan Private Spaces
古いヘッダー形式では、リージョンの種類の取得が非常に困難になります。
grep は、ほぼすべてのコマンドに役立ちます。また、常に (兄弟行を表示するために --context
フラグが必要な場合でも) 役立つ形式を表示することに注意する必要があります。
json で解析可能
テーブルの出力が増加して、CLI に適度に収まるには長くなりすぎる場合があります。--json
フラグを使用すると、プラグイン開発者はユーザーにはるかに多くのデータを提供できるようになりますが、解析する機能も引き続き与えられます。たとえば、heroku releases
を見てみましょう。
$ heroku releases
=== myapp Releases
v122 Attach HEROKU_POSTG… jeff@heroku.com 2016/04/26 19:58:19 -0700
v121 Set foo config vars jeff@heroku.com 2016/04/24 21:15:18 -0700
v120 Update REDISCLOUD b… rediscloud@addons.heroku.com 2016/04/24 11:00:28 -0700
v119 Attach REDISCLOUD (… jeff@heroku.com 2016/04/24 10:59:56 -0700
これが --json
と共に実行された場合は、各リリースの出力全体が生成されます (読みやすさのために出力全体は表示されていない)。
$ heroku releases --json
[
{
"description": "Attach otherdb (@ref:postgresql-rectangular-2230)",
"user": {
"email": "jeff@heroku.com",
"id": "5985f8c9-a63f-42a2-bec7-40b875bb986f"
},
"version": 111,
"status": "success"
}
]
ユーザーが各リリースのバージョンとユーザーだけを表示したい場合は、jq を使用して次の 2 つのフィールドだけを表示できます。
$ heroku releases --json | jq -r '"\(.[].version) \(.[].user.email)"'
122 jeff@heroku.com
121 jeff@heroku.com
120 rediscloud@addons.heroku.com
119 jeff@heroku.com
CLI コマンドが grep と jq の両方を確実にサポートできるようにすることにより、awk などのツールで必要な読みやすい UX を犠牲にすることなく、強力なスクリプト機能を提供できます。
stdout/stderr
stdout はすべての出力に、stderr は警告、エラー、および帯域外の情報 (cli.action()
など) に使用するべきです。
依存関係のガイドライン
依存関係には注意が必要です。このプラグインアーキテクチャを使用すると、プラグインに任意の npm パッケージをインストールできますが、それにはある程度のコストと潜在的な危険が伴います。
ネイティブ依存関係
Heroku CLI はネイティブ依存関係をサポートしていません。これらは、Node バージョンを更新したときに停止されます。また、ネイティブ依存関係には通常、Python を必要とする node-gyp の使用が必要であり、一般には、すべてのユーザー環境 (特に Windows) でのコンパイルで問題が発生する可能性があります。
依存関係の適切な判断
プラグインに古い、または参照されていない依存関係が含まれているかどうかを確認するには、yarn check
と yarn outdated
を使用します。
依存関係を多用していないことを確認するようください。多すぎる依存関係は、ユーザーのディスク領域が使い果たされ、インストールや更新の時間が長くなるだけでなく、プラグインが遅くなる可能性もあります。プラグインに含まれている依存関係の数や、それらの大きさを確認するには、npm ls
と du -d1 node_modules | | sort -n
を使用します。
同じバージョンを使用している場合は、重複した依存関係が他のプラグインの間で共有されます。たとえば、2 つの異なる CLI プラグインが lodash@4.6.1
を使用している場合は、その依存関係がこの 2 つのプラグインの間で共有されます。このしくみについての詳細は、この npm の記事を参照してください。
dev の依存関係の使用
プラグインでの作業にのみ必要で、その実行には必要がないパッケージには yarn add --dev
を使用します。これは、パッケージ、ドキュメントパッケージ、tslint
や eslint
などのリンターのテストに適しています。これらのパッケージは、そのプラグインのリポジトリ内で yarn
を実行した場合はインストールされますが、ユーザーが heroku plugins:install
を実行してもインストールされません。
推奨されない依存関係
次の npm パッケージは推奨できません。
パッケージ | より適切な代替手段 | |
---|---|---|
request | http-call | 極端に多すぎる依存関係を含む非常に大きなプラグイン。http-call は自動的にプロキシを解決し、再試行ロジックを追加し、その他の一般的な状況を処理します。 |
underscore | lodash | lodash には、他の多くのプラグインで使用される、Node を念頭において構築されたより多くの機能ツールが含まれています。 |