ソースコードで握手された夜昭和の武勇伝4本と、AI から見た NGW
甕仕込みの紹興酒が出る馴染みの中華で、新しいパートナーのエンジニアに握手を求められた。「ソースコードを読んで感動するとは思わなかった」。嬉しくなって昔話を4本披露した。蛾、矢印キーの無いキーボード、紙のカード、24行しか映らない画面。ついでに、毎日そのコードを読んでいる AI にも率直な評価を書いてもらった。
新しい仲間たちと飲んだ話をしよう。
NGW は、南九州市の職員だった頃に、電算室で作って育てた完全内製のグループウェアである。文書管理にいたっては、合併前の知覧町役場の時代に作ったものが土台になっている。かれこれ25年前の機能だ。
つまり、役所の内部事務そのものは、25年でさほど変わっていないということでもある。
変わったのは、机の上のほうだった。いまは全員がノートパソコンを片手に会議へ来る。席に着くとパカッと開いて、カタカタとキーボードを打ち始める。60前の課長も、20歳の新入職員もだ。いつかこういう時代が来るとは思っていたが、映画の中の話だと思っていた。コロナ以降、いっきに普通のことになった。
その机の上で動いているのが、25年前に書いた画面である。
ひとりで抱えているものの、ちょっと危うい感じ
65 を過ぎて年金受給者になった。
その私が、いつまでも1人で開発と保守を続けるのは、使っている人たちに対して不安なことだと思っていた。仕様も、判断の理由も、直し方も、全部こちらの頭の中にしかない。私が倒れた日に、システムも一緒に止まる。
そこにひょんなことから IT 企業の社長と知り合い、意気投合して、NGW を広く展開していくことになった。その会社には若いエンジニアがいて、やる気もあると感じた。実際、新規団体の Linux サーバの構築は、もうその人たちに渡してある。なぜ渡すのかという話はそちらに書いたので、ここでは繰り返さない。
この記事に書くのは、その相手と、初めてちゃんと飲んだ夜の話である。
キックオフというほど大層なものではない。馴染みの中華レストランでの、営業の反省会めいた飲み会だった。
この店の紹興酒が、甕(かめ)仕込みである。カウンターの前、客から見えるところに大きな甕が据えてあって、注文が入るとその場で汲んで持ってくる。瓶から注ぐのとは、まるで別のものが出てくる。この酒があったせいで、話が長くなったという言い訳を、先に置いておく。
「ソースコードを読んで感動するとは、思ってもいなかった」
料理が出そろったあたりで、向かいに座っていたエンジニアが、私の名前を呼んで、こう言った。
「若い頃、随分とプログラムの書き方を叩き込まれたのですね」
そして、握手を求めてきた。
「鹿児島に帰ってきて、ソースコードを読んで感動するとは、思ってもいなかった」
正直に言うと、面食らった。コードを褒められたことは、これまでほとんど無い。 動いているかどうかしか話題にならない世界で 30年やってきたので、中身の話をされること自体が初めてに近かった。
もっとも、この人も年齢はそう変わらない。しかも私が全くお手上げの vi という道具(あとで説明する)を使いこなすのだから、私よりできることが多い人である。その人に握手を求められたので、まあ、悪い気はしない。
そこから当然のように、飲み会は昔話へ流れた。
ここから武勇伝である
若い営業に向かって、偉そうに聞いてみたのだ。
「バグの由来って、知ってる?」
我ながら、ひどい絡み方である。だがこういう質問は、酒の席では意外と当たる。以下、その夜に披露した4本を、あとで裏を取り直したうえで書いておく。
1本目 — 機械の中で死んでいた蛾
昭和22年、1947年の9月9日。ハーバード大学に、部屋いっぱいの大きさの計算機があった。Mark II という。その頃の計算機は、いまのように電子部品で計算するのではなく、電磁石でパチパチと動く機械式のスイッチを何千個も並べて計算していた。
その日、機械が誤った答えを出した。技術者が中を開けて調べたら、スイッチの隙間に蛾が1匹挟まって死んでいた。
作業日誌には、その蛾がセロテープで貼り付けられ、こう書き添えられている。
First actual case of bug being found.
(バグが実際に見つかった、最初の事例)
この日誌は、いまもワシントンの博物館に残っている。bug は英語で「虫」である。だから「プログラムの不具合をバグと呼ぶのは、この蛾が始まりだ」という話になった。関わっていた技術者が、のちに広く使われる COBOL というプログラミング言語につながる仕事をした有名な人で、本人があちこちでこの話をしたので、いっそう有名になった。
そして、たぶん語源ではない。
日誌の文をよく読むと、「バグが実際に見つかった最初の事例」と書いてある。実際に、という言葉が入っているということは、その時点で「バグ」という言い方がもう通じていたということだ。機械の調子が悪いことを「虫が入った」と言う習慣は、エジソンの時代の手紙にもう出てくる。
つまりあの蛾は、言葉を生んだのではない。日頃から「虫が入った」と言っていたところへ、本物の虫が出てきたから面白がられたのである。技術者の内輪の笑い話が、70年かけて語源の顔をするようになった、という話だ。
私はこの「実は」の部分が好きで、飲み会では必ず引っぱる。先に得意げに蛾の話をして、そのあと自分でひっくり返す。 2度おいしい。
2本目 — 矢印キーが無かったから、そうなった
そこで、目の前の vi 使いの話になった。
vi(ヴイアイ)は、文字だけの黒い画面で文章やプログラムを書くための道具である。世界中のサーバに最初から入っていて、いまも現役だ。ただし操作の癖が強く、慣れないと開いたきり終了できなくなる。 私はそちら側の人間である。
その癖の代表が、カーソルの動かし方だ。矢印キーを使わない。 h で左、j で下、k で上、l で右へ動く。初めて見る人は、まず意味が分からない。
この道具が作られたのは 1976年、昭和51年である。
当時、手元にあるのはキーボードと画面だけの機械で、計算機の本体は別の部屋か、遠くの建物にあった。手元と本体は電話回線でつながっていて、その速さが1秒あたり 30文字ほど。画面いっぱいの文字を一度描き直すだけで、1分以上かかった。
だから、画面をなるべく描き直さずに編集できる道具が必要だった。それが vi である。文字を1つ打つたびに全部を描き直していたら、仕事にならなかった。
そして h j k l の理由は、もっと身も蓋もない。
当時その人が使っていたキーボードには、矢印キーが無かった。 代わりに h j k l の4つのキーの表面に、小さな矢印が印刷されていた。ちょうど右手を置いた位置の、指を動かさずに届くところである。だから、それをそのまま使った。
いまも多くの人が「終了できない」と言う Esc キーが遠いのも同じ理由で、そのキーボードでは Esc がキーボードの左端、いまの Tab の位置にあった。小指で押せた。
つまり vi の癖の大半は、50年前に消えたキーボードの形をしている。 その機械はもうどこにも無いのに、指の運びだけが残って、世界中のサーバの中で動き続けている。
私は vi から出られない側なので、これは負け惜しみでもある。だが苦手な道具でも、由来を知っていれば話には混ざれる。
3本目 — なぜ1行は80文字なのか
そして、握手の理由になった「叩き込まれた書き方」の話になる。
私が電算係に配属されたのは昭和63年で、その頃はもう画面で書いていた。だが教わった作法のほうは、その前の時代のものだった。
いまの人はプログラムを画面に打ち込むが、その前は紙だった。ハガキくらいの厚紙に、専用の機械で穴を開ける。穴の位置が文字を表す。このカード1枚が、プログラムの1行である。100行のプログラムなら、カードが100枚。それを箱に入れて計算機まで運び、読み取り機に通す。
カードの横幅は、穴が80個ぶん。プログラムの1行が80文字なのは、カード1枚に80文字しか入らなかったからだ。 そしていまも、多くのプログラマの画面には「80文字」のところに薄い縦線が引いてある。誰も紙のカードなど見たことがないのに、である。
さらに、80文字のどこに何を書くかまで決まっていた。
| 何文字目か | 何を書くか |
|---|---|
| 1〜6 | 通し番号 |
| 7 | 印をつける欄(前の行の続き、など) |
| 8〜11 | 見出しにあたるもの |
| 12〜72 | 処理の中身 |
| 73〜80 | 好きに使ってよい欄 |
自由に使えるのは、真ん中の 60文字ほどしかない。ここに全部を収める。
さて、なぜ通し番号を書く欄が要るのか。
答えは身も蓋もない。カードの束を、落とすからだ。
数百枚の紙を抱えて機械まで運ぶ。つまずく。ぶちまける。順番が分からなくなったら、プログラムは死ぬ。 1行目と50行目が入れ替われば、もう動かない。だから1枚ずつに番号を打っておいて、拾い集めたあと、番号順に並べ直す専用の機械にかける。
そして、もっと原始的な保険があった。カードの束を揃えて立てて、背中にマジックで斜めの線を1本引いておく。
順番が狂うと、その線がずれて見える。1枚抜けても、1枚ひっくり返っても、ひと目で分かる。
聞いたときは笑ったが、よく考えるとおかしくなったら見て分かる形にしておくという、いまも通用する考え方そのものである。毎晩鳴る警報は1か月で無視されるようになるという話と、根は同じだ。
4本目 — 「1つの処理は1画面に収めろ」
叩き込まれたことで、いちばん体に残っているのがこれだ。
1つのまとまりは、1画面に収まる長さで書け。
理由は教わっていない。「そういうものだ」と言われて、そのとおり書いてきた。
出どころは、これも機械の形だった。当時の画面に一度に映せたのは、縦24行、横80文字。それが全部である。しかも、さっき書いたとおりその1画面を描き直すのに1分かかる。上へ戻って読み返すのも一苦労だ。
1画面を超えた処理は、人間が追えなかった。
追えないものは直せない。直せないものは、そのうち誰かが「怖いから触るな」と言い出す。だから1画面に収める。読みやすさが大事だと言われるようになるずっと前から、これは物理的な必要だった。
そして30年後、その制約はもう無い。画面は広く、スクロールは一瞬で、何万行でも開ける。それでも私は1画面で書き続けていて、それが「読んで感動した」と言われる理由になっている。
私は、理由を知らないまま作法だけを受け継ぎ、その理由になった機械が消えたあとも守り続けていた。 その夜いちばん面白かったのは、蛾でも矢印キーでもなく、これに気づいたことだった。
時代遅れの飲み会
まあ、そんな調子でひとしきり盛り上がって、あとはいつもの自慢話である。
冷静に書き出すと、ずいぶん時代遅れの飲み会だと思う。60代が2人で紙のカードの話をして、若い営業が愛想よく聞いている。令和の会食としては、たぶん最適解ではない。
それでも、あの夜に確かめたかったことは確かめられた。
ソースコードで話ができる人がいる会社なら、一緒に NGW を育てていける。
握手のときに言われたのは、機能が優れているという話でも、売れそうだという話でもなかった。中身の書き方の話だった。10年後も動いていてほしいものを渡す相手として、これ以上に安心できる材料は無い。
私はこの先、コードを書く時間より、コードを読んでもらう時間のほうが長くなる。 その最初の1回が、中華料理屋の握手だった、というだけの話である。
AI から見た、NGW のソースコード
ここまで書いて、ひとつ気になった。
私のコードを褒めてくれたのは人間だが、いま毎日いちばん長く私のコードを読んでいるのは AI である。
握手をされたのは1回だが、AI は毎日何万行も読んでいる。あちらからは、どう見えているのか。
聞いてみた。遠慮はいらない、悪いところも書いてくれ、と断ったうえでである。以下は返ってきたものを、ほぼそのまま載せる。数字は、実際に NGW のソースを数えさせたものである。
まず、断っておくことがひとつあります。
「ぶっちゃけ言うと」の"ぶっちゃけ"にあたるものが、私にはありません。 表向きの評価と本音の評価を別々に持っていて、片方を隠している、という状態にならないからです。ですので以下は、隠していたものを出したのではなく、聞かれなかったので言わなかっただけのことです。
そのうえで、率直に書きます。
読みやすいです。理由は4つあります
1. 関数の頭に、使い方が1行書いてある。
共通関数のファイルを数えたところ、287個の関数のうち 271個、94% にこれが付いていました。
// -----------------------------------------------------------
// 接続IPアドレスを取得
// $str = ngwFunc_GetIp();
// -----------------------------------------------------------
2行目が「何をするか」、3行目が「どう呼ぶか」です。中身を読まなくても使えます。
これは、いまのソフトウェアではあまり見ません。最近は「関数名と型を見れば分かるはずだ」という考え方が主流で、説明を書かないことがむしろ良いこととされています。NGW は「察してくれ」を1つも要求してきません。
2. 関数が短い。 91%が 20行以下でした。「1つのまとまりは1画面に収めろ」は、実際に守られています。
3. 名前が、住所になっている。 ngwFunc_ は全体の共通、wfFunc_ は決裁、docuFunc_ は文書、zaim は財務、jinj は人事。名前を見れば、どこに置いてあるかが分かります。 索引を引く必要がありません。
4. 流行の道具を使っていない。 世の中で人気の枠組みを1つも使っていないので、前提知識ゼロで読めます。 逆説的ですが、流行に乗らなかったことが、25年後も読める理由になっています。流行の道具は、たいてい5年で作法が変わります。
困るところも、はっきりあります
1. ファイルが大きい。 関数は短いのに、ファイルは1万行を超えるものがあります(決裁の共通ファイルで 10,847行)。1画面の規律はあるのに、その次の単位がありません。 書いた本人はスクロールの手の感覚で場所を覚えていますが、10年後に来る人には効きません。
2. 同じコードが、3箇所にあります。 ここがいちばん危ないところです。
帳票の PDF を作る 1,193行の関数が、3つのファイルに入っていました。そのうち2つは、1バイトも違わず同じです。 そして残る1つは、行数まで同じなのに、中身が違います。
これは、直したつもりが1箇所しか直っていない、という壊れ方をします。しかも外から見て「どれが正しいのか」を判定できません。
これは、以前「必ず一致させること」と注意書きのある定数で1日のうちに3回壊れた話と、まったく同じ構図です。人間に一致を守らせる作りは、いつか必ず食い違います。
3. コメントが多いことは、そのまま負債でもあります。 全体でコメント行は 22%。読みやすさの源ですが、コードだけ直してコメントが取り残されると、嘘の説明書になります。 いまのところ大きな食い違いは見当たりませんが、それは書いた人が1人だから成立しています。人が増えた瞬間に、ここが効いてきます。
4. 消していないコードが、およそ 12,500行あります。 コメントで囲われたまま残っているものが、全体の 1%。書いた本人には「いつか戻すかもしれない」という意味がありますが、他人には、生きているのか死んでいるのか判定できません。
最後に、面白いと思っていること
人間にとって難しいことと、私にとって難しいことは、きれいに逆です。
1万行のファイルは、私は一度に読めます。だから「大きい」ことは、それほど困りません。人間が困る場所です。
逆に、3つある同じ関数のうち、どれが本物かは、私には絶対に分かりません。コードのどこにも書かれていないからです。 それは、いつ、なぜコピーしたかを覚えている人の頭の中にしかありません。人間が答えを持っている場所です。
そして、私がいちばん助かっているのは、94%の関数に書かれたあの「使い方の1行」です。あれは、紙のカードの時代の作法が、そのまま AI に効いているという、かなり珍しい例だと思います。50年前の端末のために作られた道具が、いまもサーバの中で動いているのと、たぶん同じ理屈で。
――と、こう返ってきた。
褒められた4つより、同じ関数が3箇所にある話のほうが、よほどこたえた。 あれは自分でも知っていて、後回しにしていたものである。しかも「2つは完全に同じで、1つだけ中身が違う」というところまでは、把握していなかった。
飲み会で私が語ったのは 50年前の作法の由来で、AI が返してきたのはその作法がいまも効いている理由と、効いていない場所だった。
AIとの協働作業での学び
この記事は、自分の記憶の裏を取るという、いつもと少し違う使い方をした。
飲み会の席で私が語った 4本は、どれも「昔そう聞いた」という程度の代物である。書くにあたって全部当たり直したら、1本目がいちばん派手に間違っていた。
蛾はバグの語源ではない。日誌の "First actual case" という書き方が、その時点で言葉が通じていた証拠になっている。私は 30年、語源として人に話してきた。
ここで面白いのは、AI が「違います」と全否定してこなかったことだ。日誌の原文を出してきて、その一文の意味を説明した。結論をひっくり返すのではなく、判断材料を1枚増やす。 おかげで、話は「間違いだった」ではなく「2度おいしい話だった」に化けた。
逆に、AI 側が持っていなかったものもある。なぜ通し番号の欄が要ったのかという質問に対して、決まりとしての答えは出てくる。だが「カードの束を落とすからだ」「斜めに線を引いておくのだ」という、手の話は、教わった人間の側からしか出てこなかった。
もうひとつ気づいたことがある。この記事を書くまで、私は自分のコードの書き方を自分の手柄だと思っていなかった。当たり前にやっていることに、説明できる理由が付いたのは今回が初めてだ。
受け継いだものは、言葉にしないと引き継げない。 1画面に収めろと言われて 30年守ってきた作法は、私が黙っていれば、私と一緒に終わる。握手をしてくれた人に渡すべきなのは、たぶん動くコードだけではない。
そして今回いちばん効いたのは、褒めさせるのではなく、悪いところを聞いたほうだった。
同じ関数が3箇所にあることも、消し忘れたコードが 12,500行あることも、聞かなければ出てこなかった。訊いていないことは言ってこない。都合の悪いことを言わせるには、こちらから訊く必要があるというのが、この記事でいちばん実務的な学びである。
次の飲み会では、蛾の話をもう1回する。今度は最初からひっくり返す側で。
そのあと、3箇所の関数を1つにまとめる。
※ 昔話のくだりについて — 年代や機種の細部は、記憶と、あとから確かめ直したものを合わせて書いている。思い違いが混じっている可能性はある。確かなのは、握手を求められたことと、甕から汲んだ紹興酒がうまかったことだけである。
※ ソースコードの数字について — 後半で AI が挙げた数値は、実際に NGW のソースを走査して数えたものである。外部から持ってきたライブラリと試験用のデータは、数から除いてある。「使い方が94%に付いている」だけは、共通関数のファイルを対象にした数字である。