アルゴリズムのせいではなかった。エンコーディングのせいだった。

数日のあいだ、私は自分のシステムに深く謎めいたバグがあると確信していた。ログは文字化けして出力された。データ変換の工程が、微妙に間違ったファイルを生み出した。サブプロセスは、私が期待していた出力ではなく意味不明なものを返してきた。私はロジックの欠陥を探し回った。システムのどこか、気の利いた部分にあるはずだと。

ロジックに欠陥はなかった。バグは、私のコンピュータと私とで、綴り方についての意見が食い違っていたことだった。

コードの中にはなかったバグ

何が腹立たしかったかと言えば、すべてが正しく見えたことだ。文字化けを生み出したコードを読んでも、どこにも間違いを見つけられなかった。失敗は奇妙で一貫性がなかった。あるテキストはきちんと通り、あるテキストはぐちゃぐちゃになって通り、あるファイルは完璧に開き、別のファイルは微妙に壊れていた。そのパターンのどこを見ても、修正しに行ける単一の行を指し示すものはなかった。

その一貫性のなさは、後になって分かったことだが、よくある手がかりだ。だが当時はただ、自分のプログラムが取り憑かれているように見えただけだった。

実際に何が間違っていたか:二つのプログラム、二つのアルファベット

根底にあるのはこういうことだ。コンピュータはテキストを文字として保存しない。数値として保存する。そして、その数値を文字に戻すには、どの数値がどの文字を意味するかを定めた、合意された表 — エンコーディング — が必要になる。システムの二つの部分が異なる表を使っていれば、同じバイト列がそれぞれにとって別の意味になり、一方が書いたテキストは、もう一方に誤って読まれることになる。

それが私のバグのすべてだった。私のオペレーティングシステムは古い、レガシーなエンコーディングをデフォルトにしていた一方で、私が扱っていたツールやファイルは、現代的でほぼ普遍的なものを前提としていた。二つの表がたまたま一致しているあいだは — 最も素朴な文字については一致するのだが — すべてが動いた。そして、その重なりから何かが一歩でも外れた瞬間に壊れた。テキストが意図的に壊されたことは一度もなかった。ただ、書かれたときとは別の言語で読まれていただけだった。

なぜそれがこんなにも見えにくかったか

エンコーディングの不一致は、とりわけ厄介な種類のバグだ。なぜなら、それはしばしばきれいに失敗してくれないからだ。問題を指し示す例外を投げる代わりに、寛容な変換はほぼ正しい出力を生み出しうる — 二つのエンコーディングが食い違う文字に出くわすその瞬間までは。そしてそこで、その部分だけを静かに台無しにし、何事もなかったかのように続けていく。

だから失敗は断続的で、内容に依存する。それはまさに、人を間違った場所へと探しに行かせる類いのものだ。断続的で内容依存のバグは、自分のロジックの中、自分が誇りに思っている複雑な部分の中に住んでいるに違いないように感じられる。このバグは配管の中、私が頼っていることにすら気づいていなかったデフォルトの中に住んでいた。

この種の仕事の、華やかさのない真実

学習システムを構築するうえで難しい部分とは、面白い部分 — モデル、数学、戦略 — だろうと私は想像していた。実際に難しかった部分の本当に大きな割合は、こういうものであることが判明した。テキストエンコーディング。改行コード。マシンごとに別の意味を持つファイルパス。すべての土台にある退屈なインフラ。そこでは、たった一つの間違ったデフォルトが、あなたの人生の一週間を静かに食い尽くすことができる。あなたはその上にあるエレガントなコードを見つめ、問題はきっとそこにあるはずだと確信しながら。

それは、有益な意味で、謙虚にさせられる経験だ。私を最も頻繁に止めたのは、数学であることはまれだった。配管だった。

修正:デフォルトを信じるのをやめ、一致を強制する

修理は繊細なものではなかった。私は、システムの各部分がたまたまデフォルトにしていたエンコーディングが何であれ、それに頼るのをやめた。そして、すべての境界で — あらゆるファイルの読み込み、あらゆるファイルの書き込み、あらゆるサブプロセスの起動で — 一つのもの、つまり現代的で普遍的なものを明示的に強制した。すべてのコンポーネントが、書面で、同じ表に合意させられると、文字化けは止まった。

この主たる修正と並んで、私はもう一つ、より小さな防御的な習慣を加えた。やっかいな特定の文字を、そもそもログに入れないようにすることだ — エンコーディングを正しくすることの代わりとしてではなく、最後の砦としてだ。ログは、他のすべてが火に包まれているとき、はっきりと読めることが最も必要になる、唯一の場所だ。そして私は、問題を診断するために頼っているそのツールが、同じ種類の問題の犠牲になり続けることを望まなかった。

教訓:デフォルトとは、あなたがしなかった決定だ

より深い教訓は、バグそのものより長く生き残った。あなたのスタックにあるすべての「デフォルト」は、一つの決定だ — たいていは、あなたの個別の状況を知らなかった誰かによって、しばしば何年も前に、もはや当てはまらないかもしれない理由のために下された決定だ。たいていの場合、それら受け継がれた決定は問題ないし、あなたがそれについて考える必要は決してない。それこそが、それらを危険にする一因だ。そのうちの一つが、あなたのケースにとってたまたま静かに間違っているとき、それはほとんど見えない。なぜなら、あなたはそれを意識的に選んだことが一度もないからだ — そして、あなたが決して選ばなかったものは、調べてみようと思いつく最後の場所なのだ。

私は、自分が下したことにすら気づいていなかった選択のせいで、一週間の大半を失った。今では、何かが論理的に筋の通らない形で失敗したとき、私が最初に問うことの一つは、もはや「私のバグはどこにあるのか?」だけではない。それはまた、「私は、実際には一度も決めていない何を前提にしているのか?」でもある。

— シグナルもリターンもなし、投資助言ではありません。