道具になることを目指して作られたOpen usp Tukubai を構成している49 のコマンド群。実際これらはどのようにして生まれたのだろうか。そのうちの一つで、表の合計値を求めるsm2 コマンドの生い立ちを取材した。
sm2 コマンドとは
Open usp Tukubai のsm で始まるコマンドはsum-up という表計算の世界で頻出の操作を行うシリーズだ。sm2 の場合、例えば下記のように生徒の各教科のテスト成績表があると、これに基づいて生徒毎の合計を求めるなどという用途に用いられる。
それではこのsm2 コマンドの進化の過程を見ていくことにしよう。
頻出の操作であるなら迷うことなく作ればいいじゃないかと思うだろう。いやいや、そこで冷静にならなくてはならない。「道具として本当に必要なものなのだろうか」と、考えるのだ。「既存コマンドをちょっと工夫して使えば無くてもいいかも」、そう思えるかもしれないから。
あれば便利だろうと言ってコマンドを乱立させても、数が多いと覚えきれない。そういう宿命がある。すると、存在意義の薄いもの、使用頻度の低いものからどんどん忘れ去られていく。*1
USP 研究所にも、忘れ去られて今やハードディスクの肥やしとなっているコマンドが何百とあるという。*2 そうなってしまう未来が思い浮かぶなら、作るだけ無駄だ。無駄なだけ
でなく、そのコマンドの含まれるコードを読む未来の開発者が苦労することになる。「あれ、このコマンド……。どういう仕様なんだ?知ってるコマンドで事足りるならそれで済ませといてくれればいいのに」と。
そう、コマンドを作る時には未来の開発者の姿を思い浮かべることが重要なのだ。
§こんなのがあったらきっと便利だろうなー。
§でも、いっぱい作っちゃったら不便だろうなー。
と。そんな葛藤の末、それでも「未来の開発者達も、これがあればきっと便利になるはず!」と思えたらなら作ればいい。
§末永く使われますように。
そう心で祈りながら……。
*1 どの言語も予約語が数十~百数十個程度に落ち着いている理由は、そういうところにあるのだろう。
*2 次章でいくつか紹介しよう。
作るからには末永く使われるものになれなければ迷惑だ。
だから使いやすい仕様を心掛ける。コマンドの場合、書式が作業指示の写像になっていることが重要だという。ではsm2 はそうなっているのか?
sm2 を作り始める前、表計算を行っていた作業現場では次のようなセリフが飛び交っていたという。
§その表の1 列目から2 列目をキーにして3 列目から6 列目の合計を出して!
だからsm2 は、この文章をほぼ過不足無く表現できるような書式にした。結果、決められたsm2 の書式がこうだ。
1 |
Usage : sm2 [+count] <k1> <k2> <s1> <s2> <file> |
先のセリフをこの書式に当てはめればこうなる。
1 |
sm2 1 2 3 6 その表 |
オプションの“+count” を除けば、「合計を出す」という動詞がコマンド名に、他の名詞が書式にピタリと当てはまっている。このように現場で頻繁に飛び交っている指示の写像に
なっていれば、覚え易いし、また頻繁ゆえ忘れ去られる可能性も少なく、道具として認知される存在に成り得る。
今、「動詞がコマンド名になっている」と述べたことに注目してもらいたい。
sm2 の話から少し外れるが、例え既存のコマンドのごく簡単な応用で実現できることであっても、敢えてコマンド化した方がよい場合がある。それは、作業指示として頻繁に耳にする動詞があった場合だ。
例えばTukubai コマンドにgyo というものがある。これは単にテキストの行数を求めるだけであり、“wc -l | awk'{print $1}’” とか“awk ‘END{print NR}’” などとやれば簡単に求められる。それでもコマンド、つまり道具として成立したのは、「行数求めて」という指示(動詞)が現場で頻繁に飛び交っていたこと、そしてgyo コマンドの仕様がピタリとその指示の写像になれていたからである。
このケースからも、言葉の観察がいかに大切かということがわかる。
sm2 には一つだけオプションがある。これは各々の合計を出すのに使った元の行が何行あったのかを併記するものだ。最初の成績表の場合、各生徒の受けた科目は三つだったので3 という数字を返す。後続のコマンドで平均点を求めたいという場合に有効だ。
しかしTukubai的には、どうしようもない場合でもなければオプションなど殆ど付けないという。オプションもコマンド同様、乱立させても覚えきれずに忘れ去られるからだ。
例えば有名なls コマンドの-r オプションの働きを知っているだろうか?ファイルの表示順が通常なら文字コード昇順であるところを降順にするものだ。しかし、文字コード順ではなくて大文字小文字を区別しない(辞書的な)降順にしたければ……、結局sort コマンドを併用するしかない。ならばそんなマイナーなオプションなど用意せず始めからsortコマンド併用でいいじゃないか、という意見が出てくるのと同じことだ。
オプションもまた、付けるべきか付けざるべきか。或いは増やすぐらいなら別コマンドにすべきか。よく検討したい。
最後に、sm2 の書式に対して抱くであろう疑問について答えておこう。例えば「3 番目から5 番目、それから7 番目の合計を出して」というように、k1 ~ k2 やs1 ~ s2 が不連続な指示が与えられたらどうするのかというものだ。確かにsm2 の書式では表現できない。では改良を検討しているのかというとsm2 にその予定は無いらしい。この判断も現場で飛び交うセリフに基づいている。そのような指示は稀だったのだ。そんなレアケースのために書式を複雑にしたら途端に使い辛くなる。もしそんな指示が来るならself コマンド等と組み合わせ、列が連続するように予め入れ替えるべきだ。
こういったコマンドに持たせる機能のさじ加減を見極める上でも作業指示の観察は重要なのだ。
Open usp Tukubai のビジネス版の殆どはC 言語で実装されているが、最初はどれもAWK やシェルスクリプトで作られたという。まだ定番の道具になるかわからず、廃れたり、試行錯誤によって仕様が変わる可能性も考えれば、未来の開発者にとってもコマンドの動作が追いやすい言語を使うべきだ。
こうして、sm2 も当初はAWK で実装された。残念ながらAWK で書かれていた頃のバージョンは発掘できなかったが、+count オプションをサポートしないごく簡易的なものならリスト1のように直ぐに書き起こせてしまう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
1 #! /usr/bin/awk -f 2 3 BEGIN { 4 if (ARGC < 4) 5 exit 1 6 k1=ARGV[1] 7 k2=ARGV[2] 8 s1=ARGV[3] 9 s2=ARGV[4] 10 if (k1 k2 s1 s2 ~ /[^0-9]/) 11 exit 1 12 if ((k1 > k2) || (s1 > s2)) 13 exit 1 14 if ((k1 < 1) || (s1 < 1)) 15 exit 1 16 file = (ARGV[5] != "") ? ARGV[5] : "-" 17 value[0]=0 18 delete value[0] 19 20 if (getline < file) { 21 key_old = $k1 22 for (i=k1+1; i<=k2; i++) 23 key_old = key_old " " $i 24 for (i=s1; i<=s2; i++) 25 value[i] += $i 26 while (getline < file) { 27 key = $k1 28 for (i=k1+1; i<=k2; i++) 29 key = key " " $i 30 if (key != key_old) { 31 print_total() 32 for (i in value) 33 delete value[i] 34 } 35 for (i=s1; i<=s2; i++) 36 value[i] += $i 37 key_old = key 38 } 39 } 40 41 print_total() 42 } 43 44 function print_total() { 45 printf("%s",key_old) 46 for (i=s1; i<=s2; i++) 47 printf(" %d", value[i]) 48 print "" 49 } |
sum-up という操作は表計算では頻出なので、実際sm2は多用され、重宝される道具になっているのだが、こうして50 行程で書けてしまう。
全てがそうとは限らないが、優れた道具とは概してこのように単純な構造をしているのだろう。もし何百行にも及ぶようなものができてしまったら、それは単機能なものになっておらず、道具として洗練されていないのかもしれない。
その後、sm2 コマンドはC 言語へと移植されていった。*1次第に道具としの必要性が認知され、不可欠な存在となって、そこで初めてこのコマンドに対してスピードを求められるようになったからだ。C 言語に移植後は、C 言語の鬼によって更なる高速化のための改良が続けられているという。高速化の作業に専念する為にも、LL 版で仕様をきっちり固めておくべきであろう。
sm2 のC 言語ソースファイルは、ライセンスの都合により残念ながら掲載できないが、ソースファイルはsm2.c の1つだけだ。*2 これはTukubai コマンドの殆どに言えることである。もっとも、AWK 版ソースの規模を見れば自明だろうし、同規模のUnix 標準コマンドの多くも一つだ。
一つなのでMakefileは不要。“cc -o sm2 sm2.c”などと書き、コンパイルが通るまで数秒待てば完成だ。
こんなあきれるほど簡単なコマンドやシェルスクリプトによって、一部の大手企業の業務データが管理されている*3と聞かされたら唖然するに違いない。しかし、優れた「道具」とは、そんなことをも可能にしてしまうのだ。
*1 これが、ビジネス版のusp Tukubai として現在に至る。
*2 もちろん標準ライブラリー等をインクルードしてはいるが。
*3 通信やWebUI 周りが必要な箇所では、Apache 等のHTTP サーバーアプリケーションのお世話になるのだが。
本記事の後半部分はこちらから!!