1. 導入:なぜAIは倉庫の入口をダンボールで埋めるのか?
前回の記事では、天井まで肥大化した神クラスに対し、「減算ラチェット」で逃げ道を物理的に塞ぎながら自律解体させるプロトコルを紹介しました。
1棟の手術を終えて胸をなでおろした直後、背筋が凍るような事実に直面します。
「……待てよ。自分が管理しているリポジトリ、あと20個以上あるよな?」
すべて同じ開発スタイルで、同じようにAIエージェントに実装を頼んできたコードベース群です。1つのリポジトリがあれだけ埋まっていたということは、 他の20棟の倉庫の入口も、例外なく荷物で埋まり始めている。
YouTubeやSNSを見渡せば、「AIのコードは信用できない」「1時間400行のレビューで目が痙攣する」「AIにテストを書かせるとハリボテができる(グッドハートの法則だ)」といった嘆きが溢れかえっています。
しかし、それはAI自体の欠陥でも、確率機の未熟さでもありません。問題の本質はもっと手前、 構造の力学 にあります。
2. 根本原因の因果チェーン:誰が「OKサイン」を出したのか?
現場で繰り返される悲劇を掘り下げていくと、冷徹な因果の一本道に行き着きます。
【現象】なぜ役に立たないテストが生まれるのか?
└─ ▶ テストしにくい構造だから。
(副作用とビジネスロジックが癒着し、モックで誤魔化すしかない)
【病巣】なぜテストしにくい構造になるのか?
└─ ▶ 境界を正しく分割していないから。
(関心の分離がなされておらず、単一のモジュールが何でも抱え込む)
【元凶】なぜ境界を違反するのか?
└─ ▶ そこに「何でも置いていい場所」があるから。
整理整頓・5Sの現場において、最も忌み嫌われるネガティブワードがあります。
それが 「OKサイン(=ここに何でも置いていいですよという無言の合図)」 です。
- 通路の隅に、誰かが適当に置いたダンボールが1箱ある。
- そのダンボールが「ここは仮置き場として使っていいんだ」というOKサインを放つ。
- 翌朝には全員がそこにゴミや工具を山積みにし、通路が完全に塞がる。
ソフトウェアにおける神クラス化も、寸分違わずこれと同じです。
UIのコードビハインド(MainWindow.xaml.cs)、何でも放り込める巨大な状態管理(AppState や state.rs)、ルーティングと業務ロジックが同居したHTTPハンドラ(handler.go)。
これらは最初から、コードベースの入口で 「困ったら何でもここに置いていいよ!」という巨大な青信号(OKサイン)をネオンのように点滅させていた のです。
AIは悪気があってサボっているわけではありません。
GitHub上の数十年分の「人間の妥協と手抜き」を統計的に学んだAIは、 「OKサインが点灯している場所に荷物を置くのが最も摩擦が少なく、最短距離である」 という力学に忠実に従っているだけです。
「AIのレビューが追いつかない」と目を痙攣させる人間は、散らかった現場の荷物を1個ずつ目視で確認して疲弊している作業員と同じです。
本当にやるべきは、荷物を数えることではなく、そのOKサインの看板を物理的に叩き割ることです。
3. OKサインが連鎖する構造的必然 ── エントリポイントの形骸化と「次の犠牲者」
「よし、じゃあエントリポイントを縛ればいいんだな」と安易に考えてはいけません。
AIの力学を甘く見ると、「OKサインの看板が一段奥へズレるだけ」というモグラ叩きの泥沼にハマります。
なぜコードベースの中でOKサインが次々と連鎖・再生産されていくのか。そこには逃れようのない構造的必然があります。
① 最初のエントリポイント(第一のOKサイン)
開発の初期、最も手っ取り早い置き場所は「エントリポイント」そのものです。
UIのコードビハインド、APIのハンドラ、CLIの main 関数。
ここは「ユーザーの入力を受け取り、結果を返す」という最も外側の場所であり、あらゆるモジュールを呼び出せる権限を持っています。
AIに「この機能を追加して」と頼むと、AIは最も摩擦の少ないこのエントリポイントにロジックを直書きし始めます。誰にも怒られない(型チェックも通る)ため、ここが最初の窒息倉庫になります。
② エントリポイントを縛った後の「形骸化」
そこで人間が「エントリポイントにロジックを書くな、薄くしろ」とルールを作ったとします。
すると何が起きるか。AIは確かにエントリポイントを薄くします。
main やハンドラの中身をたった数行にし、別の新モジュール(例えば AppManager や State や Service)を1個作って、そこへ処理を丸投げします。
エントリポイントを単なる「素通りするだけの土管」にして形骸化させるのです。
③ 一段奥に生まれる「第二のOKサイン」
問題はここからです。
丸投げされた先のモジュール(Service や State)の境界が厳格に定義されていない場合、エントリポイントにあったOKサインのネオン看板が、そのままそのモジュールの頭上に移設されただけになります。
AIは「ここはエントリポイントじゃないから、何でも書いていい安全地帯だ」と学習データの最頻値に沿って判断し、今度はその Service の中にDB操作も、外部API通信も、状態管理も、バリデーションも全部ドサッと積み上げ始めます。
これが、プレリサーチで見つかった以下のような病巣の正体です。
- エントリポイントの直下にぶら下がる
state.rsやAppStateが数千行に肥大化する - APIハンドラを小綺麗にした結果、裏の
handler.goやmanager.goが2,000行超のブラックホールになる - UIビハインドを避けたつもりが、直下の
ViewModelが何でも屋になって窒息する
「置き場所を物理的に縛る」とは、単にエントリポイントを薄くすることではありません。
エントリポイントから受け取った荷物を、「純粋な計算ロジック(置き場所A)」と「副作用の実行(置き場所B)」に完全に切り離し、 「その中間に何でも置ける中間管理職(神モジュール)」が生まれる隙間そのものをコンパイラと境界線で圧殺すること を意味します。
4. 一次トリアージ 「LLMへの特定命令」
精密検査にかける前に、まずはリポジトリ全体を俯瞰して「どのファイルがOKサインを発しているか」を機械的にあぶり出します。
ここでも行数(LOC)ソートなどの手動集計は行いません。リポジトリのファイル一覧・行数・直近のコミット履歴(または Repomix でまとめたツリー構造)を大容量LLMに渡し、 「OKサインの構造的疑いが強いファイルを上位からトリアージせよ」 と命じます。
【トリアージ命令プロンプト例】
添付は対象リポジトリの構成情報(ファイル一覧・行数・直近の変更履歴)です。
本リポジトリから「AIが荷物を投げ込み続けている窒息地点(OKサイン)」の疑いが強いファイルを特定してください。
単なるデータ定義や自動生成ファイル(無害な大荷物)は除外してください。以下の条件を満たす「病巣候補」をワースト順に最大3〜5件抽出し、それぞれの【選定理由(OKサインの兆候)】を添えてリストアップしてください。
-
エントリポイント直下のブラックホール:
- UIのコードビハインド、APIハンドラ、CLIのmain関数など、あらゆる権限を持っていて追記が最も容易なファイル
-
一段奥へ看板が移設された「素通りモジュール」:
- エントリポイントを形骸化させた結果、直下で全状態や全処理を丸投げされている
State/Manager/Service/ViewModel
- エントリポイントを形骸化させた結果、直下で全状態や全処理を丸投げされている
-
行数の肥大化 × 継続的な変更:
- コード行数が突出して多く(目安500〜1,000行超)、かつ直近のタスクで頻繁に触られているハブファイル
【出力フォーマット】
- ファイルパス
- 推定LOC
- OKサインの兆候(なぜAIがここに荷物を置きやすい構造になっているか)
5. 二次精密検査:大容量LLMに「連鎖したOKサイン」を告発させる
先ほどの一時トリアージの結果、コードベースのどこにOKサインが潜み、どこに荷物が押し込まれているのか。「AIが現在進行形で荷物を投げ込んでいる現場」はすぐに炙り出せます。
しかし、なぜそこに荷物が集まったのか、どうやってOKサインの連鎖を断ち切るべきかは、人間が目を痙攣させながらコードを読んでも判断がブレます。
ここで大容量LLM(Gemini等)を投入します。
注意すべきは、単にコードを渡して「リファクタリングして」と頼まないことです。そう指示すると、AIはまた自らの学習データに引っ張られ、「小綺麗に関数を分けるだけ(看板をさらに奥のモジュールへ移設するだけ)」の提案をしてきます。
プロンプトで強制すべきは、 「なぜここがOKサインになっていたのかの告発」 と 「依存矢印の完全な逆流遮断」 です。
精密検査の例(OKサイン破壊版)
フォーマット等の軽微な修正提案は一切不要です。以下の観点に絞って回答してください。
### 1. OKサインの構造告発(なぜここに何でも置けてしまったのか)
- このファイルが「何でも置ける無法地帯」になっていた根本原因(例: グローバルな可変状態、I/Oとロジックの混在、過剰な可視性)
- エントリポイントから丸投げされ、本来別レイヤーに隔離すべきなのに安易に書き足されてしまった越境ロジック(ドメイン汚染)の完全なリスト
### 2. 依存矢印の逆流遮断(置き場所の強制分割)
- このファイルを「副作用を持たない純粋ロジック」と「外部I/O・状態注入」に真っ二つに分断する境界設計
- 「何でも置いていい場所」が「次のモジュール」へ移設されるのを防ぐための、一段奥のレイヤーに対するインターフェース制約
### 3. 段階的執刀計画(前編「減算ラチェット」への引き継ぎ)
- 既存の呼び出し元を壊さないための「委譲(Delegation)ラッパー」設計
- 前編の allowlist.json に登録して機械的に削り落とすべきメソッド一覧
6. 神殺しの完了:OKサインを「進入禁止」へ
精密検査が終われば、あとは前編の手術室(減算ラチェット)へ送り込みます。
- 純粋ロジックを新モジュールへ切り出す
- 元の神モジュールは単なる「委譲ラッパー」に格下げする
allowlist.jsonに委譲メソッドを登録し、減算ラチェットCIで1機能ずつ削り落とす-
最後に入口の看板を書き換える
(Cargoワークスペースでの物理分断、可視性の制限、Linterや禁止依存ルールで「ここに勝手にロジックを書いたら即CI落ち」にする)
「ここに何でも置いていい場所」が消滅した瞬間、AIは倉庫の入口に荷物を置けなくなります。
置き場所が物理的に1箇所に縛られて初めて、AIは「正しく設計されたレール」の中を迷わずトップスピードで疾走し始めます。
7. まとめ:レビューで目を痙攣させる前に
「AIの書いたコードを人間が気合で1行ずつ読む」というメンタルモデルは、道具が電動ノコギリに進化したのに、切り口を手作業で1ミリずつ撫でて確認しているようなものです。それでは瞼が痙攣して当然です。
- 役に立たないテストが生まれるのは、テストしにくい構造だから。
- テストしにくい構造になるのは、境界を正しく分割していないから。
- 境界を違反するのは、そこに何でも置いていい場所(OKサイン)があるから。
- そしてエントリポイントだけを縛っても、AIは次のモジュールへOKサインを移設するだけ。
AI時代における人間の役割は、コードの読み書きではなく 「OKサインを消し去り、物理的なガードレールを敷くこと」 です。