docs site を Mere で書く:アプリ規模の dogfood
言語はあらゆるテストを通しても、それで何か本物を作るのが惨めなことがある。それを知る道は、本物を作ることだ —— だから Mere 自身のドキュメントサイトを、Mere で書かれたツールで生成することにした。要点はサイトではない;試みが露わにしたもの、どの primitive が実際に足りないかの優先順位つきリストと、本物のドキュメントを本物のコードに通してだけ当たる摩擦だ。
Part IV の終わりまでに、Mere は四つのやり方で走り、それらを同一の出力に保ち、その両側のコードと 話せる。そのどれもテストで検証されている。だが、どんなテストスイートも答えない問いがある:言語は 実際に何かを作るのに快いか? 言語は正しくても、なお惨めでありうる —— 手を伸ばして初めて気づく穴 だらけの標準ライブラリ、三度目に書くと不格好と判る慣用句。それを知る唯一の道は、本物を作ることで、 プロジェクトが選んだ本物は的を射ていた:Mere 自身のドキュメントサイトを、Mere で書かれたツールで 生成する。
なぜ docs site か、そしてなぜその形か
選択は意図して自己参照的だ。Mere のドキュメント —— チュートリアル、言語リファレンス、標準ライブラリ リファレンス、イディオムのページ、その他、九つのファイルにわたる数千行の Markdown —— は、閲覧可能な ウェブサイトになる必要がある。その変換を行う静的サイトジェネレータを Mere で書くことは、この試みに 二つを同時に証させる:docs が建ち、言語が本物のツールを担えると示す。「Mere で書かれたツールが Mere の ドキュメントを生成する」は、主張ではなく指させる実用性の証だ。
そして部品のほとんどはすでに、道すがら建てられた contrib ライブラリとして存在した:Markdown→HTML
変換器、{{KEY}} テンプレートエンジン、コマンドライン引数パーサ、JSON リーダ。サイトジェネレータは
大部分、それらを配線する問題だ —— Markdown ファイルを読み、それぞれを変換し、ナビゲーションバー付きの
テンプレートで包み、index とスタイルシートを書き出す。紙の上では、発明ではなく組み立てに見える。
本当の成果は gap 分析だ
dogfood を価値あるものにするのは、成果物ではない;試みが露わにするものだ。実際にジェネレータを建てる ために座ると、「標準ライブラリには穴がある」という漠然とした感覚が、どれが実際に噛むかの、具体的で 優先順位つきのリストに変わった。
いくつかの穴は本物の OS アクセスを要し、だから新しい builtin にならねばならなかった:ディレクトリの
ファイルを列挙すること、ディレクトリツリーを作ることは、言語がまだできない POSIX 呼び出しだ。他は、
コンパイラをまったく要さないと判った —— パスを繋ぐこと、basename・dirname・拡張子を取ることは、みな
数十行の普通の Mere だから、builtin ではなく小さな contrib/path ライブラリになった。フロントマター
解析 —— 各ドキュメント冒頭の --- title: ... --- ブロック —— は、YAML の最小の一片、入れ子なしの
キーと値だけを要し、これも短いライブラリになった。そのトリアージこそ、この試みの実際の成果だ:肩を
すくめるだけの「stdlib が不完全」ではなく、「これら二つは OS primitive を要し、これら四つは純粋な
ライブラリコード、この順で」—— 抽象的に推測されるのでなく、本物の必要から生まれた作業リストだ。
建てることが強いた決定は、すべて同じ調子だった:最小の正直な版を取り、残りは先送りする。フロント マターは縮小 YAML で、広大な仕様全部ではなく —— そして特に、設定として評価される Mere ソースではない。 それは強力すぎ攻撃面が大きすぎるとして端的に棄却された。ジェネレータは単一のコマンドラインプログラム として始まり、後で誰かが部品を別々に欲しがったときにだけ再利用可能なライブラリに分ける。それぞれが、 言語が説く規律を、本物のタスクの圧力の下で、言語自身のツールに適用したものだ。
本物のドキュメントだけが生む摩擦
そして、設計で回避できず、発見するしかないバグがあった。テンプレートエンジンは置換点を {{KEY}} で
印づける。Mere のドキュメントは、プログラミング言語についてのドキュメントであるがゆえ、例の中に
{{KEY}} の並びをリテラルテキストとして含む —— そしてテンプレートエンジンは、それを見て、置換
しようとした。docs を建てるツールが、docs の内容と衝突した。
これはまさに、前回が千行のプログラムをコンパイルして見つけた種類の問題だ:どんな小さなテストでも 不可視だ。小さなテストは、本物の内容が含む敵対的な入力を含まないからだ。あなたは、自分の docs が 自分のテンプレート構文について語るとは予期しない;docs が壊れて出てきたときに気づく。修正は平凡だ —— エスケープ規約か、別の区切り文字か —— だが発見こそが dogfood の価値の全部だ。本物の内容は、どんな テスト作者も書こうと思わない敵だ。
本番への準備運動
docs site を建てることは、プロジェクトの方法論 —— 紙上 trial、それから dogfood —— を、アプリケーション 丸ごとの規模で適用したもので、それは Part IV を正しい調子で閉じる:コード生成はテストを通すことで 証されるのではなく、本物のプログラムを担うことで証される。サイトジェネレータは、Mere が真のツールを 建てられることを示し、実際に重要な stdlib の穴を炙り出し、本物の使用だけが生む摩擦にちょうど当たった。
だがドキュメントを生成することは、小さな自己参照だ —— Mere についてのテキストを処理する Mere プログラム。はるかに大きなものが待っている、この連載全体が向かってきたもの:Mere 自身を処理する Mere プログラムだ。言語が docs ジェネレータを担えるなら、自分自身のコンパイラを担えるか —— レキサ、 パーサ、型検査器、評価器、コード生成器、すべて Mere で書かれ、Mere をコンパイルする? それがセルフ ホストで、次の Part の主題だ。次、Part V が開く:フロントエンド —— レキサ、パーサ、共有された構文木 —— を言語自身で書く。