【名著紹介】「UNIXという考え方」ご紹介

名著紹介

これほどまでシンプルに「UNIX/Linuxとは」について書かれた本はない。

「エンジニアとしての信念はUNIXである」とはどういうことなのか。「プログラマとしてのコンセプトはLinuxなのだ」とはどういうことなのか。

そうした、少し偏屈なエンジニアに読んでもらいたい。また、UNIX/Linuxに興味を持っている若者の手にとってもらいたい。

安心してほしい。旅のしおり程度の大きさで厚さは文庫本の半分にも満たない。しかしその中身は、多くのエンジニアを下支えしてきたUNIXという骨について、わかりやすく、かんたんに、そして記憶に残るかずかずの珠玉の言葉を添えしっかりと書かれている。

稚拙ではあるが、ざっくりと要点も付け加えたので興味を持ってもらえたなら、ネット通販などでお買い求めいただきたい。

エンジニアには必須の名著一冊、ここに紹介する。

「UNIXという考え方」
著者 Mike Gancarz 著、芳尾 桂 監訳
定価 1,760円 (本体1,600円+税)
判型 A5
頁 168頁
ISBN 978-4-274-06406-7
発売日 2001/02/24
発行元 オーム社

UNIX的なものの考え方とは何か?

UNIXをUNIXらしく使いこなしたい、UNIXらしいプログラムを作りたい人のための一冊です。
OSの背後にある哲学を、9つの定理と平易な言葉で説く
OSを使いこなすためには、その背後にある「哲学」を理解することが必要です。本書では技術的詳細には立ち入らず、その代わりに、今まで文章で表されることが少なかったUNIXの考え方を、9つの「定理」にまとめて平易な言葉で明らかにしています。

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

このような方におすすめ

UNIX系OSのユーザ、プログラマ。UNIXの世界観に興味のある人

主要目次

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

詳細目次

第1章 UNIXの考え方:たくさんの登場人物たち
1.1 UNIXの考え方:簡単なまとめ

第2章 人類にとっての小さな一歩
2.1 定理1:スモール・イズ・ビューティフル
2.2 やさしいソフトウェア工学
2.3 定理2:一つのプログラムには一つのことをうまくやらせる

第3章 楽しみと実益をかねた早めの試作
3.1 定理3:できるだけ早く試作を作成する
3.2 人間による三つのシステム
3.3 人間による第一のシステム
3.4 人間による第二のシステム
3.5 人間による第三のシステム
3.6 第三のシステムの構築

第4章 移植性の優先順位
4.1 定理4:効率より移植性
4.2 事例研究——Atari 2600
4.3 定理5:数値データはASCIIフラットファイルに保存する
4.4 事例研究——あるUNIXプログラマの道具袋

第5章 これこそ挺子の効果!
5.1 定理6:ソフトウェアの梃子を有効に活用する
5.2 定理7:シェルスクリプトを使うことで梃子の効果と移植性を高める

第6章 対話的プログラムの危険性
6.1 定理8:過度の対話的インタフェースを避ける
6.2 定理9:すべてのプログラムをフィルタにする
6.3 UNIX環境:プログラムをフィルタとして使う

第7章 さらなる10の小定理
7.1 (1) 好みに応じて自分で環境を調整できるようにする
7.2 (2) オペレーティングシステムのカーネルを小さく軽くする
7.3 (3) 小文字を使い、短く
7.4 (4) 木を守る
7.5 (5) 沈黙は金
7.6 (6) 並行して考える
7.7 (7) 部分の総和は全体よりも大きい
7.8 (8) 90パーセントの解を目指す
7.9 (9) 劣るほうが優れている
7.10 (10) 階層的に考える

第8章 一つのことをうまくやろう
8.1 UNIXの考え方:総括

第9章 UNIXと他のオペレーティングシステムの考え方
9.1 Atariホームコンピュータ——芸術としての人間工学
9.2 MS-DOS——7000万人以上のユーザが間違っているはずがない
9.3 OpenVMS——UNIXへのアンチテーゼ?

ざっくりななめよみ、鈴木めも

小さいものは美しい 「スモールイズビューティフル」

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

「伝統的なプログラマは、巨大なアメリカンプログラムによって、
  世界中の全ての問題を一つのプログラムで解決しようとする。」
「プログラムの90%はクズである。
  ただしあらゆるものの90%はクズである。」

パラメータが一行に収まらない
メソッドが画面に収まらない
コメントを読まないと何をやっているのか思い出せない
lsでモジュール名が多すぎて画面の端から消えていってしまう
まだ開発中なのにエラーメッセージの意味を思い出せない
整理するためにソースコードを印刷している自分に気がついた

一つのプログラムには一つの事をうまくやらせる 「わかることは分けること」

「UNIXユーザーは、自分が何をしているのかをわかっている。
  何をしているのかわからないのなら、ここにいるべきではない」
「一つの事をうまくやるようにプログラムを作れないのであれば、
  おそらく問題をまだ完全に理解していない。」

a)ユーザーとの対話が必要か。パラメータではだめか
b)入力データは特殊フォーマットが必要か。フォーマット変換プログラムがすでにシステム上にないか。
c)出力データは特殊フォーマットが必要か。通常のASCIIファイルではだめか。
d)新しいプログラムを書かずとも似たような機能を持つ他のプログラムがあるのではないか。

「一つの事をうまくやるようにプログラムを作れないのであれば、
  おそらく問題をまだ完全に理解していない。」
「しのびよる多機能主義。
  プログラマはいつだってプログラムを遅くする方法を見つける。」

一つの事をうまくやるようにアプリケーションを書けば、それは必然的に小さなプログラムになる。
小さなプログラムは単一機能になる傾向があり、単一機能のプログラムは小さくなる傾向がある。

出来るだけ早く試作する 「反復と協調」

「試作によって学ぶ。早い試作はリスクを減らす。
 「正しく」やっている時間などない」
「「なにができるか」
  むしろ重要な事は、「なにができないか」を知る事だ。」

三つのシステム
1.第一のシステム
 第一のシステムは正しくやっている時間などない。
 第一のシステムは追い詰められた人間が作る。
 第一のシステムのコンセプトは人々の想像力を刺激する。
 第一のシステムは一人かせいぜい数人からなる小さなグループで作られる。
 第一のシステムは高い情熱によって推進され開発は急速に進む。
 第一のシステムは実に性能がよい。

2.第二のシステム
 第二のシステムは第一のシステムで証明されたアイデアを継承する。
 第二のシステムは委員会が設計する。
 第二のシステムは委員会によりものごとを全て公開の場で自分自身の正当化のために議論を進める。
 第二のシステムは第一のシステムの成功に便乗し分け前にあずかろうとする自称専門家で作られる。
 第二のシステムは自称専門家によりリポジトリ、進捗管理ツールが導入され計画は遅延する。
 第二のシステムは自称専門家のプログラムにおきかえられ贅肉がつき象のようにゆっくり動く。
 第二のシステムは「最初の設計のひどい欠点を見違えるように改善」され多機能となり無知が使う。
 第二のシステムは三つのシステムの中で最悪のシステムである。

3.第三のシステム
 第三のシステムはこれまでのシステムへの反抗から生まれる。
 第三のシステムの名前が変わり、オリジナルのアイデアはもはや常識となる。
 第三のシステムは第一と第二のシステムの最良の特徴を組み合わせる。
 第三のシステムは設計者にとってようやく「正しく」やる事が出来る。
 第三のシステムはユーザーが実際に使用する機能しか含まれない。
 第三のシステムはディスク、メモリ、CPUサイクルなど最適なバランスが実現されている。
 第三のシステムは提供される性能レベルも良くバランスがとれている。

第一のシステムとして「試作」を1ナノ秒でも早く作り、
 第一のシステムと第二のシステムのサイクルを反復と協調し、
  第三のシステムに向かって協力しながら進んでいく。

効率より移植性 bashとawkとsed

「最も効率の良い方法は、
  ほとんどの場合「移植性」に欠ける。」
「移植か死か。優れたソフトウェアは移植され成長し、
  それ以外は取り残され捨てられる。」

UNIXにおいてそれはシェルスクリプトしかない。
次のハードウェアはもっと速く走る。だからプログラムを速くするという誘惑に負けない。
わずかな速度を求めてCで書き直さない。それは時間の無駄だ。

シェルスクリプトをあれこれいじる余裕が一瞬でも生じればほとんどのプログラマは
 a) 新しい機能をいくつか付け加えようとする
 b) スクリプトそのものを洗練し、実行速度を高めようとする
 c) その一部、または大部分をCで書き直してパフォーマンスの向上を図ろうとする。

「最も効率の良い方法は、
  ほとんどの場合「移植性」に欠ける。」
「移植か死か。優れたソフトウェアは移植され成長し、
  それ以外は取り残され捨てられる。」

DQ1カートリッジ(64kb)用のコード
 自分のプログラマ人生で最も効率の良い、そして移植の難しいコード」を書いた。
 命令をデータとして扱い、データを命令として扱った。
 走査線が画面の右端から左端に引き返すまでの間を狙って命令を実行した。
 メモリ節約のためありとあらゆる技を駆使した。
 こうしてできあがったコードは芸術品と言えるほど見事なものだった。
 フォルクスワーゲンのビートルに20人ほど詰め込むようなものだった。
 そして保守担当者にとっては究極の悪夢でもあった。

出力結果はASCIIフラットファイルに保存する 中間ファイルは作らない RDBは使わない

「動かせないデータは死んだデータだ。」

出力結果はASCIIフラットファイルに保存する。
安易と稚拙な知識でRDBを使わない。
むやみに中間ファイルをはき出さない。
素晴らしいシステムは中間ファイルI/Oがゼロで、
全てがメモリ上で稼働する。よってそこそこ高速に動く。

ソフトウェアを梃子として使う 

「良いプログラマはよいコードを書く。
  偉大なプログラマは良いコードを借りてくる。」

梃子の支点をいかに自分のほうに近づける事が出来るか
独自技術症候群を避け、すでにあるものにクリエイティブな付加価値をつける
独自技術症候群は創造性を伸ばさない。

「良いプログラマはよいコードを書く。
  偉大なプログラマは良いコードを借りてくる。」

シェルスクリプトによって梃子の効果と移植性を高める パイプ

「私は人生で二度しか奇跡を見た事がない。
  一つは核融合、もう一つは複利だ
   少量のものを繰り返し掛け合わせていく事で、
    やがて奇跡的な規模に達する。」

シェルスクリプトには恐ろしいほどの梃子(てこ)の効果がある
シェルスクリプトは梃子の降下で時間も節約する
シェルスクリプトはCより移植性が高い

「熟練プログラマはシェルスクリプトを熱心に使う。
  あなたもまたそうするべきだ。」
「UNIXの源流は高水準の抽象化モデル「シェルスクリプト」であり、
  それは今も普遍である。」
「私は人生で二度しか奇跡を見た事がない。
  一つは核融合、もう一つは複利だ
 少量のものを繰り返し掛け合わせていく事で、
  やがて奇跡的な規模に達する。」アインシュタイン

シェルスクリプト一行はおよそ1万倍の複利を生む

echo who | awk '{ print $1 ; }' | sort | uniq | sed -e "s/  /,  /g" ;
echo   177
who    755
awk   3411
sort  2614
uniq   302
sed   2093
---------------------
    9.353

処理をパイプでつなぎ処理全体を一行で完結させる。
「ひとつのことをうまくやる」の良い事例だ。

function sh_func_getTitle() {
  TITLE=$(echo ${URLGETOPT} | \
    while read line ;do
      if echo "$line" | grep -i "title=" > /dev/null; then
        echo "$line" | \
          sed -e "s/^.*title=\x27//g" \
              -e "s/\x27.*$//g" \
              -e "s/\r//g" \
              -e "s/<[^>]*>//g" \
              -e "s/^[●○■□△▽]//g"; 
      fi
    done
  );
}

全てのプログラムをフィルタとして設計する

 メソッド間の入力をstdin、出力はstdoutを使用する
オンメモリでコマンドフィルタとして稼働する。

function trim(){
  if [ -p /dev/stdin ]; then
    cat - ;
  else
    echo -n ;
  fi | sed -e 's/^ *//g' -e 's/ *$//g'
}

実行結果

echo "      ほげ      " | trim ;
ほげ

以下でも良い。

function trim(){
  awk '{ print $1; }' | sed -e 's/^ *//g' -e 's/ *$//g'  </dev/stdin
}

実行結果

echo "      ほげ      " | trim ;
ほげ

並行して考える

 並列処理が可能なメソッドを積極的に書く

並列処理が可能なメソッドを積極的に書く

メソッドの並列処理

#!/bin/bash

##
#
#
function cmd(){ 
  echo "Hello, $1!"; 
}
##
#
#
function sh_xargs(){
  export -f cmd
  yes | head -1000 | xargs -n1 -P4 -I % bash -c "cmd %"
}
##
#
#
sh_xargs ;

木を守る

 UNIXはドキュメントを忌み嫌う

UNIXユーザーは紙のドキュメントを忌み嫌う。不要なドキュメントを印刷して整理する事はしない。
ソースコードが実体であり、高水準のドキュメントとなるようプログラムする。

「ざっくり」シリーズのご紹介

【アルゴリズム ソート比較】ざっくりわかるシェルスクリプト20
https://suzukiiichiro.github.io/2022-11-02-01-sortcomp-suzuki/
【アルゴリズム クイックソート】ざっくりわかるシェルスクリプト19
https://suzukiiichiro.github.io/2022-11-01-01-quicksort-suzuki/
【アルゴリズム シェルソート】ざっくりわかるシェルスクリプト18
https://suzukiiichiro.github.io/2022-10-27-01-shellsort-suzuki/
【アルゴリズム マージソート】ざっくりわかるシェルスクリプト17
https://suzukiiichiro.github.io/2022-10-19-01-mergesort-suzuki/
【アルゴリズム 連結リスト】ざっくりわかるシェルスクリプト16
https://suzukiiichiro.github.io/posts/2022-10-18-01-list-suzuki/
【アルゴリズム 再帰】ざっくりわかるシェルスクリプト15
https://suzukiiichiro.github.io/posts/2022-10-07-01-algorithm-recursion-suzuki/
【アルゴリズム キュー】ざっくりわかるシェルスクリプト14
https://suzukiiichiro.github.io/posts/2022-10-06-01-algorithm-queue-suzuki/
【アルゴリズム スタック】ざっくりわかるシェルスクリプト13
https://suzukiiichiro.github.io/posts/2022-10-06-01-algorithm-stack-suzuki/
【アルゴリズム 挿入ソート】ざっくりわかるシェルスクリプト12
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-insertionsort-suzuki/
【アルゴリズム 選択ソート】ざっくりわかるシェルスクリプト11
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-selectionsort-suzuki/
【アルゴリズム バブルソート】ざっくりわかるシェルスクリプト10
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-bubblesort-suzuki/
【アルゴリズム ビッグオー】ざっくりわかるシェルスクリプト9
https://suzukiiichiro.github.io/posts/2022-10-04-01-algorithm-bigo-suzuki/
【アルゴリズム 2次元配列編】ざっくりわかるシェルスクリプト8
https://suzukiiichiro.github.io/posts/2022-10-03-01-algorithm-eval-array-suzuki/
【アルゴリズム 配列準備編】ざっくりわかるシェルスクリプト7
https://suzukiiichiro.github.io/posts/2022-10-03-01-algorithm-array-suzuki/
【アルゴリズム 配列編】ざっくりわかるシェルスクリプト6
https://suzukiiichiro.github.io/posts/2022-09-27-01-array-suzuki/
【grep/sed/awkも】ざっくりわかるシェルスクリプト5
https://suzukiiichiro.github.io/posts/2022-02-02-01-suzuki/
【grep特集】ざっくりわかるシェルスクリプト4
https://suzukiiichiro.github.io/posts/2022-01-24-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト3
https://suzukiiichiro.github.io/posts/2022-01-13-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト2
https://suzukiiichiro.github.io/posts/2022-01-12-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト1
https://suzukiiichiro.github.io/posts/2022-01-07-01-suzuki/

【TIPS】ざっくりわかるシェルスクリプト
https://suzukiiichiro.github.io/posts/2022-09-26-01-tips-suzuki/

書籍の紹介

【tac】bash/シェルスクリプトマニアックコマンドあれこれ1

【tac】bash/シェルスクリプトマニアックコマンドあれこれ1

【アルゴリズム ソート比較】ざっくりわかるシェルスクリプト20

【アルゴリズム ソート比較】ざっくりわかるシェルスクリプト20