Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
107 lines (55 sloc) 13.4 KB

写像的プログラミング ― rev,seq,AWKコマンドに見るコマンドの在り方

この記事は、POSIX原理主義 Advent Calendar 2016の21日目である。

申し遅れたが、我は秘密結社シェルショッカー日本支部の321である。さて、今日はrevやseq、AWKコマンドなどを見ながら、コマンドのあるべき姿について語ろう。

1.プログラムは作業手順書の写像であれ

そもそも何のためにコマンドを使うのかよく考えてみるがいい。コンピュータに作業を指示するためであることに疑いの余地はないな。

人間の世界では、指示する回数が増えていき、かつ常に手順が決まっているなら、それをまとめて「作業手順書」というものを作るであろう。それがコンピュータの世界では単に「プログラム」と呼ばれているに過ぎん。故に、コンピュータプログラムとは人間世界の作業手順書の写像であるべきだ。つまり「用いる言語や単語が違っているだけで、内容の本質は全く同じ(=意訳せずに直訳で済む)」というのが理想だ。なぜなら、写像で済む程度の差であれば、読み書きが容易でメンテナンスが非常に楽だからだ。

写像程度の差であれば、業務の現場に立つ素人でも辞書を片手にプログラムを読み書きできるようになる。慣れてくれば覚えてしまえるレベルだ。つまり**プログラマという専門家への依存度を減らせる。**現場の人間が直接読み書きできれば、プログラマを介して伝言ゲームのようにして、システムがいつの間にか意図せぬ代物に化けてしまう危険性が減る。(参考⇒顧客が本当に必要だったもの

プログラムが、作業手順書の写像であることがいかに重要かということがわかっただろうか。それを今時のプログラムときたら、作業手順書からどんどんかけ離れた得体の知れん姿にしおって……。それを読み解くのに一体どれだけの時間をかけろというつもりか!メンテ地獄に陥るのも当たり前だろうが。

2.写像的プログラムの5条件

では、作業手順書の写像になっているプログラムとは具体的にどんな姿をしているのか。

それにはまず、お前たちが日頃目にする作業手順書を思い浮かべることだ。

  • 箇条書きになっていて、各手順の文章は短い(1.あれする、2.これする、……)。
  • 作業手順数はそれほど多くない。
  • 分岐やループはほどんどなし(あってもごく簡単なもの)。
  • その手順を実施するか否かの条件判定もほとんどなし(あってもごく簡単なもの)。
  • 変数・関数に相当するものもほとんどなし(条件判定も分岐もほとんどないから当然)。

どうだ、普段目にするものはどれもこうなっているとは思わんか? つまり、人間が読む作業手順書というのはだいたい上から下へ素直に読めるようになっておるのだ。

もし容赦無く、分岐やループ、条件判定、変数、関数といったものが作業手順書にあったら何が起こるか考えてみろ。作業ミスが頻発してあちこちの現場で事故が起こるぞ。せっかく作業をマニュアル化して、昨日か一昨日に入ってきたバイトにやらせたくても、これでは危なかしくて任せられんな。だから作業手順書というものは、どこの現場でもこうして単純な作りになっておるのだ。

なに、「コンピュータはプログラムの実行を間違えないから関係無いだろう」だと? 愚かな……。プログラムをメンテするのは一体誰だ? 人間だろうが! だから写像的なプログラムを書くべきであり、今言った5つの特徴(写像的プログラムの5条件)をプログラムにも持たせることが重要なのだ。

3.コマンドは動詞、引数は目的語

いよいよ本題、コマンドの在り方だ。

先ほど言った「写像的プログラムの5条件」を満たすうえで重要なことは、コマンドが動詞的なものになっているということだ。手順書の各項目で一番重要かつ必須なものは何だ?言うまでもなく動詞だ。「あれしろ」、「これしろ」、という単語がなければ手順書にならんからな。

逆に主語など不要だ。「新入りのお前はあれしろ」、「10年以上のベテランはこれしろ」などと、主語をつけて手順書を作るくらいなら、初めから新入り用の手順書とベテラン用の手順書に分けろ。

一方、目的語は必要なこともある。単に「ファイルを消せ」と指示しても、どのファイルかわからなければ話にならんからな。

以上をまとめると、写像的プログラムの各手順項目に必要な情報は「動詞」と時々「目的語」だけで、その他は余計だ。必須の動詞、時々必要な目的後をプログラムの世界に写像するとなったら、必然的に動詞はコマンドに、目的語は引数に、ということになるな。

4.良いコマンド、悪いコマンド

ここまでの説明を踏まえ、UNIX上に存在する各コマンドの良し悪しを検証する。

revコマンド

いきなりPOSIX外のコマンドを例に挙げてすまぬが、本記事のテーマにもなっているrevコマンド、こいつは最高だ。「文字列を左右反転する」という動詞的意味が、revに見事写像されている。

どの文字列を左右反転するかという目的語については、省略すれば「標準入力を」、記述すれば「そのファイルを」ということになって、これもまた綺麗に写像されている。

コマンド、そしてプログラムとはすべてこうありたいものだな。

lsコマンド

こいつはあまり良くない。そもそも我が言う前からUNIX哲学的に悪いコマンドの見本として有名だ。

lsは「ファイル一覧を表示する」という動詞的意味を綺麗に写像しているように思えるが、オプションが死ぬほど多い。そしてオプション次第で動作が様々に変化する。例えば-lをつければ「ファイルの詳細を一覧表示する」になるし、-rをつければ「ファイルを降順で一覧表示する」になる。つまり、オプションがある時はオプションを含めて1つの動詞的な存在になる。オプションが目的語ではなく動詞の一部というのは、コマンドが洗練されていない証拠だ。

例えば-rオプションは「降順に並べ替える」という意味であるが、これはファイルの一覧表示をするという動詞とはまた独立した動詞的意味を持っている。つまり、lsというコマンドは単機能になりきれておらず「肥満体」なのだ。降順の並べ替えをしたければ、sortという別コマンドで別手順に独立させた方が写像的になるではないか。(確かに、lsとsortを組み合わせると1ファイル1行に表示が強制されるし、打ち込むキーの数もls -rより増えるから対話的用途では使いづらいのはわかる。あくまでプログラム化した時の話だ。)

一方、-lオプションはそうもいかない。ファイルの詳細情報を引っ張り出してくる機能はlsコマンドから分離できないので-rオプションのようにはいかない。しかし、ls -lにはよくllというエイリアスを充てるではないか。まさにそうすればいいのだ。このようにして、動詞的意味を複数のコマンドに分離できないものは逆にコマンド自体に取り込んで新たな別コマンドにすればよいのだ。

このようにして、無駄にたくさんあるオプションを整理していけばコマンドは洗練され、理想の写像的プログラムに近づいてゆく。

ついでに言うと我ら組織のリッチー大佐がデザインした、utconv(日常時間とUNIX時間の相互変換をする)コマンドも同様に悪い例だ。日常時間→UNIX時間の時は単にutconvだが、UNIX時間→日常時間の時はutconv -rと書くことになっておる。今の説明を聞いたお前たちならこういうコマンドはどうすべきかもうわかるな。UNIX時間→日常時間には別名のコマンドを作るべきなのだ。

AWKコマンド

こいつは最悪だ!

プログラム中に出てくるawkの3文字を見せられて、その行で一体どんな処理がなされているか想像がつくか? つかんだろうが! つまり、まったく動詞的でもなければ写像的でないということだ。

具体的な処理を把握したくば、その後ろに書かれているAWKスクリプトを読み解かねばらない。写像的プログラムの5条件の一つ「箇条書きになっていて、各手順の文章は短い。」を真っ向から無視して、写像的プログラムらしさを崩壊に至らしめる。AWKを多用してプログラムを書いたつもりでいるなど大間違いだ!

とはいえ、AWKが無いと乗り切れない局面があるのもまた事実。だから絶対に使うなとは言わん。そもそも我らが作ったコマンドの中身を見るとAWKが多用されておるからな……。

だがな、「言ってることとやってることが違うぞ矛盾してるな、おい」などと勘違いするなよ。AWKが必要な局面もあることと、写像的プログラムを書くのが理想という、相反する命題の狭間で、普段はなるべくAWKを使わずに済むようにすべく、在るべき仕様のコマンドを作っているのだ。いわばAWKを隠蔽するためにコマンドを作っているようなものだ。

恐らくOpen usp Tukubaiコマンドを作った者たちも同じ思いがあったに違いない。それだけでなく、seqコマンドの作者も同じはずだ。数列を表示するなどAWKがあればできるのに、何故あえて再発明したかといったらそれくらいしか理由を思いつかんからな。しかもこいつは数列の開始、終了、増分の引数を、オプションの引数ではなく、スペース区切りの単独引数にしているところがなおいい。可読性が高く写像的であるし、打ち込むキーの数も少ないからな。コマンドの在り方をよくわかっておる。

こうやって、どのコマンドが優れているかいないかを検証していくうち、revコマンドやseqコマンドは、コマンドの在り方をわかっていると感じた。だが残念ながらどっちもPOSIX外のコマンドだ。そこで、両コマンドに敬意を表してPOSIX原理主義に基づいて、移植をしてみた。

5.まとめ(POSIX原理主義との関係)

「プログラムは作業手順書の写像、コマンドは動詞、引数は目的語であるべき」という話のどこがPOSIX原理主義と関係あるのかわからぬか? ならば教えてやる。

聖典にも書かれているがな、POSIX原理主義とはもともと、開発の現場でこれまで散々メンテナンス等で痛い目に遭ってきたプログラマ達が生み出したサバイバル術なのだ。痛い目を見て、死に物狂いで楽になる方法を探し求めた結果、UNIX哲学に出会った。そしてこれを進化・発展させる形で交換可能性 という考え方にたどりつき、今のPOSIX原理主義が確立したといっていい。そしてこの、写像的プログラミングも同様にUNIX哲学から生まれたものである。

つまり、POSIX原理主義も、写像的プログラミングも、そして母体となったUNIX哲学も、プログラマがプログラマという職業で長く生きていくための手段であるから、どれも皆大事な考え方だ。

逆に言えば、POSIX原理主義という今現在一番表面にある考え方だけに注目しても何も見えて来ぬ。見えて来ぬから批判だけが先に立つ。愚かなことだ。

すべてのプログラマ達が賢く、強く、そしてプログラマとして長く生き延びられること願う。では、今日はさらばだ!