AIが書けるコードの境界は、難しさでは引かれていない

同じ日に、二つの仕事をAIに投げた。一方は記事の下書きを検査する処理で、frontmatter のキーが揃っているか、書かないと決めた言い回しが混ざっていないか、本文の数値が証跡から引けるかを見る。もう一方は、その検査が付けた点数をどこから書き直しに回すか、という閾値の決めごとだった。
前者は動くところまで行った。後者は、案を出させては私が「これは違う」と返すだけの往復になり、私の手元では近づかなかった。作業として難しいのは、どう考えても前者のほうである。
難しいほうが通り、簡単なほうで止まった
同じことが他でも起きていた。
記事の進行状況を記録する台帳を SQLite に置いている。夜に走るバッチと手元の操作が同時に触ったときに壊れないようにする部分は、私が書いたコードの中でも面倒な部類に入る。それでも任せて通った。壊れ方がテストに出るからだ。落ちたところを渡せば、次の周でだいたい直ってくる。
一覧ページのカードの余白と折り返しも任せた。私は CSS が得意ではない。それでも自分で書くより速く済んだ。画面を開けば、崩れているかどうかが目で分かる。
launchd から走らせている夜のバッチが、コマンドを見つけられずに落ちたときも任せた。走るか落ちるかがそのまま結果として返ってくる。
一方で、記事のタイトルは最後まで自分で書くことになった。案はいくらでも出てくるし、形は整っている。読むと違う。どう違うのかを言葉にできないまま何周かして、結局私が書いた。難しい仕事ではない。閾値のときと同じ止まり方だった。
難易度の順に並べ替えると、任せられたものと任せられなかったものが混ざる。別の軸で並べ替えると、混ざらない。
境界は、判定がどこにあるかで引かれている
AIが書けるコードと書けないコードを分けているのは、コードの難しさではない。そのコードが正しいかどうかの判定が、自分の外にあるかどうかである。私はそう考えている。
判定が外にあるというのは、正しくないときに自分以外の何かが先に教えてくれる、ということだ。テストが落ちる。画面が崩れる。処理が止まる。使う人が困る。このとき私は判定装置ではなく、判定を受け取る側に回れる。だから何周でも回せるし、回すたびに近づく。近づくことが見込めるなら、難しさは時間の問題に変わる。
判定が内側にあるというのは、正しくないと言えるのが自分しかいない、ということだ。この抽象は後で効く。この名前なら読み手に通じる。この閾値なら手元の感覚と合う。ここでは私が判定装置なので、周を重ねるたびに私の時間だけが減っていく。減ったぶん、自分で書いたほうが安く済む点に近づいていく。
境界の外側にあるのは、難しいコードではない。判定を私から取り出せないコードである。
「言葉にできるなら、もう実装できている」
ここに強い反論がある。
判定を外に出せという助言は、言うだけなら簡単だ。判定を言葉にできるほど問題を理解しているなら、その時点でもう実装できている。仕様を厳密に書く作業は、実装そのものに近づいていく。しかも実際の開発では順序が逆で、出てきたものを見て初めて「これは違う」と分かる。生成は翻訳ではなく探索であり、判定は探索の結果として後から立ち上がる。だから「判定が先にあるか」で線を引くのは、順序を取り違えている——これが反対側の言い分である。
前半は私も受け入れる。判定は書く前に全部は決まらない。私も決めていない。
受け入れたうえで、区別は残ると考えている。判定が事後に立ち上がるのは構わない。立ち上がった瞬間に、それが自分の外に出ているかどうかが問題なのだ。出てきたものを見て「ここが違う」と指せるなら、判定はもう外に出ている。指した先を渡せば次の周がある。
私がタイトルで止まったのは、違うと言えたのに、何が違うかを指せなかったからだ。指せないものは渡せない。渡せないものは、周を重ねても手元の情報が増えない。反論が言う探索は、探索の結果を受け取る器がある場合にだけ探索になる。器が自分の中にしかないとき、起きているのは探索ではなく、同じ判断を何度もやり直す作業である。
だからこの主張は「先に仕様を書け」ではない。違うと思ったときに、何が違うかを指せる形になっているかを見ろ、である。実装より前に全部を決めることは要求しない。
境界を動かすのは、モデルではなく判定の置き場所
この見方を取ると、やることが変わる。
境界を内側へ広げたいとき、私が触るのはモデルでもプロンプトでもない。判定の置き場所である。テストを書くのはその手段の一つだが、一つでしかない。画面を開けば分かる形にする、落ちたら止まる形にする、間違ったときに自分が困る形にしておく。どれも判定を外に出す作業だ。
そして、出せないと分かったものは自分で書く。これは敗北ではなく仕分けである。書き直しの閾値は私には外に出せなかったので、自分で決めた。決めてしまえば、それ以降は外に出た判定として機械のほうが使える。
AIの使い方が上手いように見える人がいる。その差は指示の書き方ではなく、判定を外に出す手数の多さだと私は思っている。
この見方が外れるとき
いくつか条件が思いつく。
頭の中にあると思っている判定が、過去に自分が書いたコードの中に既に現れている場合。リポジトリを渡せば推測される。規約ファイルやリポジトリの要約を渡す仕組みは、そこを狙っている。この方向が効く範囲では、境界は内側へ動く。私の言う「取り出せない」は、今の私の手の届く範囲での話でしかない。
「好み」だと思っていたものが、実はどちらでもよかった場合。閾値を決め直したことがあるが、前の値と新しい値のどちらでも記事の出来は変わらなかった。あのとき収束しなかったのは、判定が自分の中にあったからではなく、判定がそもそも無かったからだ。この場合、私の言う境界は判定の所在ではなく判定の不在を指している。自分の「好み」を過大に見積もる癖が私にはある。
判定が外にあるのに収束しない状況が続く場合。そのときは線の引き方が間違っている。
この記事に証跡は無い。手元で見た並び方と、そこから立てた見方を書いた。読んだ人が自分の手元で並べ替えて、別の軸のほうが揃うと言うなら、私はそちらを聞きたい。