http://fishshell.com/docs/current/design.html の翻訳です。
概要
fishを設計するための設計原理を述べます。 fishの設計は3つの高いレベルの目標があります。 これらは、
- 他のシェル言語で行えるすべてのことがfishでも行えるようにすべきです。たとえ外部コマンドに頼ることになろうとも。
- fishはユーザフレンドリーであるべきです。ただし、表現力を犠牲にすべきではありません。表現力と使い易さの間のトレードオフは慎重な設計で回避できます。
- 可能な限り上記の目標を崩すことなく、fishはPOSIXの構文に従うべきです。
これらの高レベルな目標を達成するために、fishの設計はいくつかのより具体的な設計原理に依存します。 以下に根拠といくつかの例を用いてそれらを示します。
直交性の原則
シェル言語は少数の直交した機能を持つべきです。 同類だが同一ではない2つの機能が存在する場合は、どれか1つは削除されるべきです。 残った1つの機能はより高機能かつ、どちらの機能の一般的なユースケースの全てを扱えるほどに一般化されるべきです。
根拠
複数の同類の機能は言語を巨大化させます。 そして、それは学習を困難にします。 また、ソースコードの肥大化させ、プログラムをメンテナンス・更新を困難にさせます。
例
- ヒアドキュメントは パイプライン で echo コマンドを使うこととほとんど変わらないので不採用です。(訳注:「string trim 複数行文字列リテラル」でも代用可能)
- サブシェルとコマンド置換とプロセス置換はとても類似性が強いです。fishは コマンド置換 のみをサポートしています。それ以外はブロックまたはpsub標準シェル関数 で実現できます。
- 別名定義 と シェル関数 の双方を持つことは混乱を招きます。特別にどちらも制限と欠点があるからです。fishの関数はいずれの構文の欠点も存在しません。
- POSIXのクオートの仕様は馬鹿げています!とくにシングルクォートは!!
応答性の原則
シェルはいつでもユーザに対して応答可能であるべきです。 それがたとえcontendedや応答しないファイルシステムであってもです。 ユーザが開始したアクション…たとえばコマンド実行…に対してブロックすることのみ許されます。
根拠
悪いパフォーマンスはユーザが直面する複雑さを増加させます。 なぜなら、それはユーザに遅いユースケースとして認識させ、迂回するようにさせるからです。 そしてそれはとてつもなくイライラさせられます。
例
- シンタックスハイライト や オートサジェスチョン のような機能は非同期ディスクI/Oでなければなりません
- シェル立ち上げ時はfork()とディスクI/Oを最小限にすべきです。その結果、システムに負荷がかかっているときでさえfishを立ち上げることが可能です。
「設定可能性」は諸悪の根源
プログラム内のすべての設定オプションはユーザが本当に求めているものを理解するにはあまりにも馬鹿げている場所です。 また、設定オプションはプログラムとそれを実装したプログラマの双方の障害を考慮すべきです。
根拠
さまざまな設定オプションをメンテナンスするのは悪夢のように困難です。 なぜなら、特定の設定の組み合わせによって引き起こされた潜在的なバグの数はすぐに問題になってしまうからです。 設定オプションは多くの場合、後方互換性の問題を引き起こすコードを再実装するときのコードについての仮定を意味します。 しかし、多くの場合は設定オプションを作るのは防ぐべきです。 なぜなら、プログラムが最良、あるいはそれに近い動作ができるほど十分賢いのならば、そんなオプションは存在すべきではないからです。
例
- fishは シンタックスハイライトの色をユーザに設定させる ことを許しています。なぜなら、fishは端末でデフォルトで使っている色について知る由がないからです。色設定によっては文字が読めなくなる恐れがあります。全プログラム・端末エミュレータがfishへ送信する色情報のために、ユーザが主として文字色を定義するのが最適解でしょう。
- fishは以下の設定項目をユーザが指定できないようにしています
- コマンドライン履歴ファイル名
- 記憶する履歴数
- 異なる言語のサブスタイル(?)
- 他のシェルが共通して持っている設定オプションの数々
設定可能性の悪について特筆すべきことは、いくつかのシェルに存在するとても便利な機能の数々が、デフォルトではオフになっていることです。 たとえば、zshもbashも コマンド固有の補完 をサポートしています。 しかし、このような補完機能はbashは標準装備ではありませんし、zshではデフォルトではオフになっています。 zshは他にも以下のような便利な機能がありますが、デフォルトではオフになっています。
- ワイルドカードを含む文字列のTAB補完
- 補完用のページャ機能
- ヒストリファイル
ユーザフォーカスの原則
プログラムを設計するときは、最初に直感的でパワフルなプログラムをどのように作るかを考えるべきです。 実装の問題については、一旦ユーザインターフェースを設計してから考えるべきです。
根拠
この設計方針は他とは異なります。 なぜなら、新機能の設計に取り掛かるべき方法を説明しているのであって、新機能が何であるべきかについて説明しているのではないからです。 何ができるか、そして何をするのが簡単かについてフォーカスする問題は、あまりにも多くの実装が存在することです。 これは、ユーザがシェルがどのように動作するのかを推測する基礎となるシステムについて多くのことを知っていなければならないことを意味します。 また、その言語はしばしばかなり低レベルであることも意味します。
例
- シェルへの入力はたった1種類、コマンドのリストのみであるべきです。ループ、条件分岐、変数への代入は通常のコマンドによって実現されるべきです。
- ビルトインコマンド とシェル関数の差はなるべく小さくあるべきです。それらは他のコマンドとまったく同じように 引数展開 されるべきであり、パイプラインのどの場所でも使えるべきであり、 入出力リダイレクト をサポートすべきです。
- 他のシェルでは、偽の変数スコープを実現するためのコマンド置換をするときにはfork()しています。それに対して、すべてのfishコマンドは同一プロセスから実行されます。fishは真の スコープ を実現しています。
- すべてのブロックは end で終えます。(訳注:fiやesacやdoneなどではない)
見つけやすさの原則
プログラムはユーザがなるべく簡単に機能を見付けられるように設計すべきです。
根拠
機能が見付けやすいプログラムは短時間で初心者が上級者になれます。 なぜなら、ユーザはただ単にプログラムを使うだけで上級者になっていくのですから。 (訳注:僕がfishに惚れ込んだ最大の理由!zsh歴15年をたった3日で凌駕したのだ)
GUIプログラムがCLIに勝る点は主に「機能の見つけやすさ」です。 GUIプログラムでは画面を見てボタン・メニューその他ウィジェットの挙動を推測するだけで、すべての共通の機能を見つけられます。 CLIプログラムで機能を見付ける伝統的な方法はmanページ経由です。 manページは、他のプログラムを使い始めるときと、次に同じプログラムを使うときに新しい情報を記憶するのに必要になります。
例
- すべてがTAB補完できるべきです。そして、すべてのTAB補完には説明文がついているべきです。
- すべての文法エラーとビルトインコマンドのエラーが起きたときには、間違いの場所と関連ヘルプページをエラーメッセージで示すべきです。できる限り、エラーはシンタックスハイライトで赤文字で表示すべきです。
- ヘルプマニュアルは読みやすく、シェルから簡単にアクセス可能で、完全で、多くの具体例を含むべきです。(訳注:本当、助けられました。とてもわかりやすい)
- シェル言語は一貫しているべきです。そのため、ユーザは一度コマンド・引数の文法を理解してしまえば、言語全体を理解でき、TAB補完で新機能を見付けられるようになります。
最後までお読みいただき、ありがとうございました。参考になれば嬉しいです。