UNIX哲学

UNIX哲学（ユニックスてつがく、英: The UNIX Philosophy）とは、ソフトウェア開発の文化的な規範と哲学のまとまりであり、UNIX OS開発者たちの経験に基づくものとされている。その内容は発言者によって異なり、以下の点に留意が必要である： UNIXが開発された1971年から10年以上後の発言が大半である 発言者にはUNIX開発と関わり合いが希薄な人物も含まれている UNIXを生み出したケン・トンプソンやデニス・リッチーは"哲学"(philosophy)という表現をしていない 哲学に反して商用UNIXには大規模で多機能なソフトウェアが含まれている場合がある すなわち、この哲学は当初から一貫して存在していたわけではなく、UNIXに関わる全ての人の共通認識でもなく、UNIXの現在や過去の状況を必ずしも的確に表現しているわけでもない。妥当性や有効性が普遍的に立証されているわけでもない。UNIXに関心を示す人々の一部の希望、願望、理想にすぎない。 1978年のBell System Technical Journalにダグラス・マキルロイ他によって記載されている： それぞれのプログラムが1つのことをうまくこなすように。新しい仕事をするために、新しい「機能」を追加して古いプログラムを複雑にするのではなく、新しいプログラムを構築する。 すべてのプログラムの出力が、まだ見ぬ別のプログラムの入力になること。出力に余計な情報を入れないように。厳密に列挙された入力形式やバイナリ形式は避ける。インタラクティブな入力にこだわらない ソフトウェアはもちろんOSであっても、早期に、理想としては数週間以内に試せるよう設計・構築する。不器用な部分は躊躇なく捨てて作り直すように 回り道をしても、使い終わった後に捨てることになっても、プログラミングの作業を軽減するためには、お手伝いさんではなくツールを使う その後、en:Peter H. Salusが『A Quarter-Century of Unix』（1994年）にまとめている： 一つのことをうまくやるプログラムを書く 連携するプログラムを書く 普遍的なインターフェースであるテキストストリームを扱うプログラムを書く 1974年のUnix論文で、ケン・トンプソンとデニス・リッチーはUNIXの設計で以下を考慮したと述べている： プログラムを書いたり、テストしたり、実行したりするのが簡単に行えるようシステムを設計した 当初のバージョンでは1人のユーザーしかサポートしていなかったものの、システムを対話的に使用できるようにした 適切に設計された対話型システムは、「バッチ処理」システムよりもはるかに生産的で満足のいくものであると信じている サイズの制約は経済性だけでなく、かえって設計をエレガントにする方向に働いた すべてのUnixソフトウェアはUnixの下で保守されている パイプの発明者でありUNIX創始者の一人でもあるマキルロイはこの哲学を以下のように要約した： これがUNIXの哲学である。 一つのことを行い、またそれをうまくやるプログラムを書け。 協調して動くプログラムを書け。 標準入出力（テキスト・ストリーム）を扱うプログラムを書け。標準入出力は普遍的インターフェースなのだ。 — ダグラス・マキルロイ、UNIXの四半世紀 この哲学は「一つのことを、うまくやれ」とさらに要約されることがある。このうち3つめだけがUNIXに特有である。 （注意: これは直接にはUNIX哲学ではない。強い結びつきのあるC言語の記述ではある） ロブ・パイクは Notes on Programming in C で以下をプログラミングの格言として提案している。UNIX哲学と共通点がある。 ルール1: プログラムがどこで時間を消費することになるか知ることはできない。ボトルネックは驚くべき箇所で起こるものである。したがって、どこがボトルネックなのかをはっきりさせるまでは、推測を行ったり、スピードハックをしてはならない。 ルール2: 計測すべし。計測するまでは速度のための調整をしてはならない。コードの一部が残りを圧倒しないのであれば、なおさらである。 ルール3: 凝った(Fancy)アルゴリズムは n {\displaystyle n} が小さいときには遅く、 n {\displaystyle n} はしばしば小さい。凝ったアルゴリズムは大きな定数を持っている。 n {\displaystyle n} が頻繁に大きくなることがわかっていないなら、凝ってはいけない（ n {\displaystyle n} が大きくなるときでさえ、ルール2が最初に適用される）。 ルール4: 凝ったアルゴリズムはシンプルなそれよりバグを含みやすく、実装するのも難しい。シンプルなアルゴリズムとシンプルなデータ構造を使うべし。 ルール5: データはすべてを決定づける。もし、正しいデータ構造を選び、ものごとをうまく構成すれば、アルゴリズムはほとんどいつも自明のものになるだろう。プログラミングの中心は、アルゴリズムではなくデータ構造にある。 ルール6: ルール6は存在しない。 ルール1と2は、ドナルド・クヌースの格言「早すぎる最適化は諸悪の根源である」を言い換えたものである（最適化 (情報工学)#最適化する時期も参照）。 ケン・トンプソンはルール3と4を「疑いがあるときは総当たり（brute force）を使え」と言い換えている。これらは設計哲学のKISSの例でもある。 ルール5はフレッド・ブルックスが以前に「人月の神話」で述べている。ジョン・ベントレーの Programming Pearls にも同じ原則が述べられている。これは「スマートなデータを使うつまらないコードを書け」と短縮されこともある。また「データ構造が十分に良いものなら、それを扱うアルゴリズムは平凡であるべきだ」というガイドラインの実例でもある。 ルール6はモンティ・パイソンの「ブルース・スケッチ」をふざけて引用したのものである。 1994年、マイク・ガンカーズ（X Window System開発チームの一員）は、UNIXで得た経験と、同僚プログラマーや他分野のUNIX利用者との議論を活かし、以下9つのUNIX哲学を創出した[要出典]： スモール・イズ・ビューティフル (小さいものは美しい) 各プログラムが一つのことをうまくやるようにせよ できる限り早く試作せよ 効率よりも移植しやすさを優先せよ 単純なテキストファイルにデータを格納せよ ソフトウェアを梃子(てこ)として利用せよ 梃子の効果と移植性を高めるためにシェルスクリプトを利用せよ 過度の対話的インターフェースを避けよ すべてのプログラムをフィルタとして設計せよ 以下の教義は重要性が比較的低いとされ、UNIX哲学として普遍的に合意されるものではなく、場合によっては現在も激しく議論されている（例：モノリシックカーネルとマイクロカーネル）。 好みに応じて自分で環境を調整できるようにせよ OSのカーネルは小さく軽量にせよ 小文字の短い名前を使え 森林を守れ 沈黙は金なり 並行性を考えよ 部分の総和は全体よりも大きい 90パーセントの解決を模索せよ 劣るほうが優れている (より悪いことは、より良いことだ) 階層的に考えよ リチャード・P・ガブリエルは、UNIXの優位性のひとつは「より悪いことは、より良いことだ」（"Worse is better"）という哲学にあると述べている。ここではインターフェースと実装の両面がシンプルであることが、他のいかなる特性（正確さ、堅牢さ、完全さ）よりも重視される。 その一方で、以下のような疑問も投げかけている。例えば、もしI/Oやsleepなどのシステムコール（例：read()、write()、open()、select()）により、あるプロセスがカーネル内で長期間ブロックされているときに、そのプロセスにシグナルが通知されたら何を行うべきだろうか。システムコールが完了するまでの長い間（場合よっては永遠に）シグナルは遅延されるべきなのか。はたまた、カーネルはシステムコールをあとで再実行できるように状態を保存した上で一時中断し、シグナルハンドル、システムコールへと再復帰すべきか。いずれも時間はかかるがシステムコールを完遂する完全性を考慮したものである。 しかしながら、このようなケースではケン・トンプソンとデニス・リッチーは完全性よりもシンプルさを好む。聡明期のUNIXはシステムコールを終了させ、エラーを素早く通知する - Interrupted System Call（システムコール実行中にユーザーが割り込みを発行）、エラー番号4（EINTR）。後にシステムコールは再開されない。この実装はI/Oシステムを設計、理解しやすくする事に利点がある。 エリック・S・レイモンドは著書『The Art of UNIX Programming』で、UNIX哲学を "Keep it Simple, Stupid" （KISS原則、「シンプルでつまらないものに保て」）という工学哲学として要約した。いかにこの哲学がUNIXの文化的規範として適用されているか信念を述べている。しかしながら、以下のルールを違反した例も比較的簡単に発見できる。 モジュール化のルール クリーンなインターフェースで接続されるシンプルなパーツを書け。 プログラムは、単純な部品同士を明確な定義を持つインターフェースでつなぎ合わせたものとして書かれるべきだ。そうすれば、問題は局所的なものとなり、プログラムの一部は将来のバージョンで新機能をサポートするために交換することができる。このルールの狙いは、複雑で長くて読めないコードをデバッグする時間を節約することにある。 明瞭さのルール 明瞭さは独創性よりも良い。 開発者が最も意志疎通を図るべき相手はコンピュータではなく、プログラムを読み、保守を行う自分を含めた開発者であるかのようにプログラムを書くべきである。このルールは、将来そのコードを扱う人にとって、コードが読みやすく、理解しやすいものにすることを目的とする。 合成のルール 他のプログラムと接続できるようプログラムをデザインせよ。 開発者は他のプログラムと簡単に通信できるプログラムを書くべきである。開発者がプロジェクトを、過度に複雑な一枚岩のプログラムではなく、小さくてシンプルなプログラムに分解することを目的とする。 分割のルール ポリシーをメカニズムから分離せよ。インターフェースをエンジンから分離せよ。 開発者はプログラムのメカニズムとプログラムのポリシーを分離する必要がある。一つの方法として、プログラムをフロントエンドのインターフェースと、そのインターフェースが通信するバックエンドのエンジンに分ける等がある。メカニズムを崩さずにポリシーを変更できるようにし、結果的にバグの数を減らすことを目的としている。 シンプルさのルール シンプルさを求めてデザインせよ。複雑にしなければならない場合に限り、複雑さを加えよ。 開発者はシンプルなデザインを心掛けるべきである。プログラムを小さく分かりやすい協調性を持った部品に分割する方法を模索せよ。開発者が「緻密（ちみつ）で美しく複雑な」だが、実際にはバグだらけのプログラムを書いてしまうことを防ぐためのものである。 倹約のルール 開発者は大きなプログラムを書くことを避けるべきである。これは開発時間の過剰投資を防ぐことが目的である。膨大な作業の数々を破棄したくないというプログラム所有者の気持ちが原因で起こる。小さなプログラムは、最適化やメンテナンスが容易であるだけでなく、廃棄する事も容易である。 透明性のルール 透明性を求めてデザインせよ。調査とデバッグが簡単になる。 開発者は将来そのプロジェクトに参加する開発者が、自分の思考プロセスを明瞭に理解できるように書き、有効な入力と正しい出力を容易に識別できる入出力形式を使用することによって、可視性と発見性を設計する必要がある。デバッグにかかる時間を短縮し、プログラムの寿命を延ばすことを目的としてる。 頑丈さのルール 頑丈さは透明性とシンプルさから生まれる。 開発者は透明性と発見力を高める設計をすることで、堅牢なプログラムにする必要がある。理解しやすいコードは、複雑なプログラムでは予見できないような状況に対してストレステストを行いやすいため。開発者が堅牢で信頼性の高い製品を構築できるようにすることを目的とする。 代表のルール 知識をデータに織り込め。するとプログラムのロジックをつまらなくて頑丈なものにできる。 開発者は選択に迫られたとき、プログラムの手続き的なロジックよりも、データをより複雑にすることを選択すべきだ。なぜなら、人間にとって複雑なデータは、複雑なロジックに比べて理解しやすいからだ。プロジェクトに携わるどの開発者にとってもプログラムを読みやすくすることで、プログラムの保守を可能にすることを目的とする。 最小限の驚きのルール インターフェースデザインにおいては、常に驚きが最小限であるようにせよ。 開発者はユーザーが期待する潜在的な知識の上に構築されるプログラムを設計する必要がある。例えば、電卓のプログラムでは、'+'は常に足し算を意味するはずである。開発者が直感的に使いやすい製品を作ることを奨励することを目的とする。 沈黙のルール 余計な出力をすべきではない。他の開発者にとってただ邪魔なだけである。 開発者は不要な出力をしないようにプログラムを設計する必要がある。他のプログラムや開発者が、冗長な出力を解析することなく、プログラムの出力から必要な情報を選び出せるようにすることを目的とする。 修復のルール 失敗しなければならないときは、騒がしく、かつできるだけ早く失敗せよ。 開発者は故障の原因が特定しやすく、診断しやすい、つまり「音を立てて故障する」プログラムを設計する必要があります。プログラムからの不正な出力が入力となり、他のコードの出力が検出されずに破損することを防ぐことを目的とする。 経済のルール プログラマの時間は貴重である。プログラマの時間をコンピュータの時間より優先して節約せよ。 現在のマシンサイクルは1970年代の価格と比較して相対的に安価であるため、開発者はマシンタイムよりも開発者タイムを重視すべきだ。プロジェクトの開発コストを削減することを目的とする。 生成のルール hand-hackingは避けよ。 開発者は手書きでコードを書くことを避け、代わりに抽象的な高水準プログラムを書いて、コードを生成する必要がある。ヒューマンエラーを減らし、時間を節約することを目的とする。 最適化のルール 洗練させる前に原型（プロトタイプ）を作れ。最適化する前に原型が動くようにせよ。 開発者はソフトウェアを磨く前にプロトタイプを作るべきである。開発者がわずかな利益のために過剰な時間を費やすことを防ぐことを目的とする。 多様性のルール あらゆる「ただ一つの本当の方法」という主張は信じるな。 開発者はプログラムが柔軟でオープンであるように設計する必要がある。このルールは、プログラムを柔軟にすることで、開発者が意図した以外の使い方を可能にすることを目的とする。 拡張性のルール 未来に向けてデザインせよ。未来は思ったよりもすぐにやってくる。 開発者は、プロトコルを拡張可能にし、他の開発者がプログラムのアーキテクチャを変更することなく簡単にプラグインできるようにし、プログラムのバージョンを表記するなどして、将来を見据えた設計をする必要がある。開発者が書いたコードの寿命を延ばし、実用性を高めることを目的とする。 これら規範の多くはUNIXコミュニティの外でも受け入れられている――最初にUNIXが採用したときはそうでなかったとしても、後にそうなった。また、多くはUNIXコミュニティ独特のものではなく、UNIXコミュニティから生じたわけでもない。にもかかわらず、熟練のUNIXプログラマーはこれらの考え方を組み合わせたものをUNIXスタイルの基礎として受け入れる傾向がある。 GNUプロジェクトによる標準的なUNIXプログラムの代替（diffやfind等）がUNIX哲学に従うものであるのか、あるいはそれを誤解しているのかは議論の分かれるところである。おそらく、UNIXに古くから関わる人々のうちのいくらかは後者を主張するであろう。なぜならGNUプロジェクトのツール群はしばしばUNIXのものよりも十分に大きく、また機能も豊富だからである（GNUはコーディング標準において、いくつかの点でUNIXと同じにしないことを薦めている）。 GNU以前の1983年、ロブ・パイクはUNIXの基本的なツールについて、BSDによって拡張された機能のいくつか（代表例として挙げられたのは、cat に制御コードを文字に変換して可視化させる -v ）の仕様が、UNIX的でないとした批判がある。UNIX哲学に従えば、cat -v の機能は独立したフィルタで果たされるべきである。本来「連結」コマンドである cat が、単にストリームを読んで書くだけの目的に流用されることが多いとはいえ、それに加えてあれこれと機能を持つべきではないという考え方もある。 同様にして批判されたls コマンドのオプション：出力を表示される幅に合わせて整形する機能は十分に便利であるが、UNIX哲学に従えば column コマンドをパイプで繋ぐ必要があり、これは煩わしいと考える事もできる 。 「UNIXはシンプルである。必要なのはそのシンプルさを理解する素質だけである。」 - デニス・リッチー 「UNIXはユーザが愚かなことをするのを止めるために作られたのではない。小器用なことをするのも防いでくれるのだ。」 - ダグ・グウィン 「UNIXはユーザフレンドリーだ。誰彼構わずフレンドリーになるわけではないだけだ。」- スティーブン・キング 「UNIXを理解しない人々は、それを不十分に再発明することになるだろう」 - ヘンリー・スペンサー Plan 9 from Bell Labs パイプ (コンピュータ) en:The Elements of Style – UNIX哲学の着想の源の一つ。 en:The UNIX-HATERS Handbook ソフトウェア工学 The Unix Programming Environment by Brian Kernighan and Rob Pike, 1984 Notes on Programming in C, Rob Pike, September 21, 1989 UNIXの1/4世紀, Peter H. Salus, Addison-Wesley, May 31, 1994 (ISBN 0-201-54777-5、ISBN 4756136591) Philosophy — from The Art of Unix Programming, Eric S. Raymond, Addison-Wesley, September 17, 2003 (ISBN 0-13-142901-9、ISBN 4756149480) Final Report of the Multics Kernel Design Project by M. D. Schroeder, D. D. Clark, J. H. Saltzer, and D. H. Wells, 1977. UNIXという考え方―その設計思想と哲学, Mike Gancarz, ISBN 4274064069