エンジニアの頭の中

フリーランスエンジニアが書く技術系ブログです。

「UNIXという考え方―その設計思想と哲学」という本を読んだ(要約・書評)

どんな本?

UNIXという考え方―その設計思想と哲学」は、プログラム開発におけるUNIXの思想について述べた本です。

少し古い本ですが、その内容からは、共感できる点や学ぶ点が多いです。その考え方は、現代においても有効な点が多々あると思います。 こちらは、日本語に翻訳されたもので、原著は「The UNIX Philosophy」になります。

この本の要点

この本では、UNIXの考え方として重要な点を、9つの「定理」として語られています。

定理

  1. スモール・イズ・ビューティフル
  2. 一つのプログラムには一つのことをうまくやらせる
  3. できるだけ早く試作を完成する
  4. 効率より移植性
  5. 数値データはASCIIフラットファイルに保存する
  6. ソフトウェアの梃子を有効に活用する
  7. シェルスクリプトを使うことで梃子の効果と移植性を高める
  8. 過度の対話的インタフェースを避ける
  9. すべてのプログラムをフィルタにする

それぞれの定理とされているものについて、要点を以下にまとめてみました。 あくまでも、これらは、著者の主張を断片的に抽出したものです。実際の書籍では、細かい説明や、具体的な実例が豊富に記載されているので、ぜひ書籍を読んでみることをお勧めします。

定理1.スモール・イズ・ビューティフル

プログラムは、本来の目的のみを実現する小さなプログラムであるべきで、関連はするものの、本来の目的とは異なる機能を持った、巨大なプログラムを作るべきではないと述べています。

例として、ファイルをコピーするプログラムを挙げており、コピー元からコピー先へ、ファイルの内容をコピーする処理(目的の処理)の前後に必要になるファイルの存在有無のチェックなどの処理は、他の小さなプログラムに任せるべきということです。UNIXの実例として、ファイルの存在有無にはtestコマンドが使用されている点を挙げています。

小さなプログラムのメリット

  • わかりやすい
  • 保守しやすい
  • システムリソースにやさしい
  • 他のプログラムと組み合わせやすい

定理2.一つのプログラムには一つのことをうまくやらせる

一つのプログラムでは、一つの機能のみを提供すべきです。そのためには、以下の様な点を確認すべきです。

  • ユーザーとの対話が必要か?パラメータをファイルやコマンドラインから渡すだけでは足りないのか?
  • 入力データは、特殊なフォーマットが必要なのか?フォーマット変換は、他のプログラムでできるのではないか?
  • 出力データは、特殊なフォーマットが必要なのか?ASCIIではダメなのか?
  • 似たような機能を持った、他のプログラムを使い回す事が出来ないか?

この「一つのプログラムには一つのことをうまくやらせる」という考えかたから外れてしまったUNIXにおける実例が、lsコマンド であり、純粋なlsコマンドは、ファイルとディレクトリの一覧を順不同の一列で表示するものですが、その後のバージョンのlsは、表示内容を複数列に整えて表示したり、様々な機能を提供するために、大量のオプションがある点を指摘しています。

定理3.できるだけ早く試作を作成する

とにかく、早く試作せよとのこと。 アプリケーションの設計を固めてから、実装にかかるのではなく、コードを書き、早く試作することによって、うまくいく点、うまくいかない点を早く知り、リスクを減らし、結果として製品のリリースは早まるとしています。 具体的なプロセスとして、以下の3点を繰り返します。詳細な仕様書は、以下の繰り返しが終了した後、もし必要であれば作成します。

  1. 短い機能仕様書の作成
  2. コードを書く
  3. テスト

定理4.効率より移植性

プログラムは、効率が良く高速であることよりも、移植性の高さを重視すべきと述べています。また、データにおいても、移植性の高さを重視しています。

効率の良いコードは、ハードウェアの性能を活用して、高速な処理を実現するが、同時にグラフィクスアクセラレータやキャッシュメモリなどを活用するため、移植性が犠牲にされてしまいます。単一のアーキテクチャでしか動かないプログラムでは、利用機会が狭められ、マーケットが限られてしまうというデメリットだと主張しています。また、ハードウェアは、時間と共に進化して高速になっていきます。ハードウェアの性能向上により、現時点で低速だったプログラムは、十分高速に動かせる可能性があります。そのため、わずかな処理時間の短縮のために、コードを書き換えるようなことは時間の無駄です。 そうなった時に、プログラムが新しいハードウェアでも稼働できるよう、移植性が重要になります。

高い移植性 を実現するための、具体的な手段の例として、プログラムをシェルスクリプトで書くことを挙げています。 シェルスクリプトで書いたコードは、C言語で書いたコードより高い移植性を持ちます(OSにもよりますが)。

定理5.数値データはASCIIフラットファイルに保存する

データは、人が読めてかつ簡単にエディタで編集ができるASCIIで保管するべきで、バイナリや特殊なファイルシステムは使用するべきではないと述べています。

ASCIIであれば、多くのUNIXコマンド(awk、diff、grepsed、sort、tail … )でもデータを扱うことができます。 ASCIIであることによって、バイナリと比較して、効率が落ちる可能性は否めないでしょうが、高い効率を求められるプログラム以外では、ほとんど問題とはならないですし、また、マシンの性能の向上によっても、この点は改善されていくでしょう。

データをASCIIテキストで保管してく事は、アプリケーションを移植する際に、そのデータの移植も簡単にします。

定理6.ソフトウェアの梃子を有効に活用する

梃子を有効に活用するために、以下の点について、それぞれの重要性を語っています。

  • コードを書くのではなくコードを借りる
  • 独自記述に陥らないようにする
  • 他人にコードを使わせる
  • 自動化する

「よいプログラマはよいコードを書く。偉大なプログラマはよいコードを借りてくる」と始まり、他人の仕事の成果を自分の仕事に取り入れるべきで、それこそが、効率よくソフトウェアを作成する方法であり、借りられたコードも価値を高めるため、借りる側、借りられた側共にメリットがあると述べています。

車輪の再発明による無駄や、コードの移植性を下げることになりかねないことから、独自技術に進んでいくことに注意を促しています。コードの梃子を有効に活用にするには、他人のコードを借りるだけではなく、自分のコードを他人にも使わせるべきで、UNIXが成功した原因も、コードを自由に使えたことにあると言っています。

また、ソフトウェアの梃子を活用するには、人が作業するのではなく、とにかくマシンを働かせるべき、自動化すべきとしています。

定理7.シェルスクリプトを使うことで梃子の効果と移植性を高める

プログラムの梃子の効果を最大限得るためには、シェルスクリプトを効果的に使用しなければならないと述べています。

シェルスクリプトは、他人の書いたプログラム(シェルスクリプトC言語で書かれたプログラムなども)を、容易に使う事が出来ます。たった1行のスクリプトコードでも、パイプ「 | 」で連結して、複数のコマンドを連携して処理させる事が出来ます。

定理8.過度の対話的インタフェースを避ける

プログラムを起動して、ユーザーと対話しながら処理を行っていくインタラクティブなインタフェースのことを、「拘束的インタフェース」と表現しており、これに対して批判的な考えを示しています。 拘束的インタフェースのデメリットとして、以下の点を挙げています。

  • コンピュータが、人による入力を待っている時間は無駄であり、コンピュータの処理能力を活かしきれていない。
  • コマンドパーサーが大きく醜くなる。(他の定理に反することになる)
  • 対話的インタフェースは、UNIXの長所である「プログラム同士の会話」を行う事が苦手であり、シェルスクリプトに組み込む事が困難になるため、他のプログラムと結合する事が難しく、プログラムの梃子の効果を得る事が出来ない。
  • プログラムを繰り返し実行する事が困難で、スケーラビリティに欠ける。(拘束的インタフェースであるadduserコマンドで数千人のユーザー追加を行う事が現実的でない事を例に挙げている)

定理9.すべてのプログラムをフィルタにする

全てのプログラムは、何かしらの入力を受け付け、処理した結果を出力するフィルタであるとの考えを示しています。 また、データはコンピュータが作るのでなく、人間が作るもので、コンピュータはデータを変換するものだと述べています。

プログラムをフィルタ化するために、設計として、守るべき点は以下のとおりです。

  • データの入力にはstdinを使用する。
  • データの出力にはstdoutを使用する。
  • 帯域外情報の出力にはstderrを使用する。

プログラムをフィルタとして作成することを意識しておけば、拘束的インタフェースを避ける事ができ、梃子の効果をえる事ができます。

感想

「定理1.スモール・イズ・ビューティフル」の思想は、UNIXに限らず、現代のソフトウェア開発においても、大いに役に立つ考え方だと思っています。特に、保守のしやすさや、他のプログラムと組み合わせやすいという点は、重要な点だと思っています。

基本的にプロダクトの一部となるコードは、将来に渡ってメンテナンスしていくものです。最初にコードを書いた本人が、将来もそのコードのメンテナンスをし続けていくとは限りません。現在のためだけでなく、将来の担当者のメンテナンスのしやすさのためにも、小さなプログラムの作成を心がけるのは良いと思います。

「定理6.ソフトウェアの梃子を有効に活用する」では、「コードを借りるべき」という主張があります。効率や作り込むリスクを考えれば、当たり前のことではあるのですが、公開されているオープンソースのライブラリや、使用しているフレームワーク、プロジェクト内で作成済みのライブラリなどで、すでに提供されている機能を、「コードを借りる」事をせず、自前で作成してしまうというケースをよく見かけます。(逆によく理解せずに無闇に他人コードを借りて問題が起きるケースもありますが・・・)

「コードを借りる」事の実現のしやすさのためにも、「小さなプログラム」である事は重要です。コードを借りることができず、類似のコードを書く羽目になると、開発工数の増加や、不具合リスクの増加、保守性の低下など、良くないことばかりですが、ソフトウェア開発の現場では、頻繁に起きている問題だと思っています。

その他の「定理」としているものについても、大体は納得のいくもので、現実の多くのシーンにおいて通じるものではないかと思います。

ちなみに、定理については6章までで語られていて、その後の 「第7章 さらなる10のUNIXの考え方」では、実際のUNIX人が、どのようなシーンでどのように考え行動しているかを、著者の経験から紹介しているのですが、この章もなかなか面白いです。

総評すると、知識を深めるという点でも、面白さという点でも、とても充実した本だと思います。 ページ数は多くないですが、内容は濃く、値段も安いと思います。

日頃、UNIXに触れるかどうかに関わらず、エンジニアの人には、ぜひ読んでもらいたい一冊です。

書籍情報

表紙

※原著はKindle版が販売されていますが、翻訳版は紙の本しか販売されていないようです。

目次

  • 第1章 UNIXの考え方:たくさんの登場人物たち
  • 第2章 人類にとての小さな一歩
  • 第3章 楽しみと実益をかねた早めの試作
  • 第4章 移植性の優先順位
  • 第5章 これこそ梃子の効果!
  • 第6章 対話的プログラムの危険性
  • 第7章 さらなる10のUNIXの考え方
  • 第8章 一つのことをうまくやろう
  • 第9章 UNIXとその他のオペレーティングシステムの考え方