序
Coding Agent が実用段階に入ってから,設計の問いは少し変わった. 以前は「このコードをどう書くか」が中心だったが,いまは「このコードのどこまでを Agent に委ねるか」が同じくらい重要になっている.
私はこの「Coding Agent にどれだけ身を任せるか」という度合いを,Agenty と呼ぶことにしたい.
0は全く Agent に委ねない状態100は完全に Agent に委ねる状態
これはモデルの性能指標ではない. リポジトリとアーキテクチャの設計指標 である.
重要なのは,Agenty は高ければ高いほど良い値ではない,ということだ.
本当にやりたいのは repo 全体を 100 にすることではない.
どこを 0 に寄せ,どこに高い Agenty を置くべきかを設計すること である.
この観点で見ると,たとえば fuckin-strict-nuxt-dmmf が示している *.def.ts / *.impl.ts / *.test.ts の分離は,単なるファイル命名規則ではない.
あれは「どの層の Agenty を低く保ち,どの層の Agenty を上げてよいか」を repo に埋め込む試みとして読める.
ただし本質は Nuxt でも Vue でもない. この考え方は,もっと framework-independent に捉えられる.
Agenty は局所的に設計されるべき
Agenty は,repo 全体に一律でかけるノブではない. レイヤごとに異なる値を持つべきだ.
私はだいたい次の 3 層で考えている.
| 層 | 目安の Agenty | 理由 |
|---|---|---|
def / static rule |
0 ~ 20 |
ルール,型,境界,状態遷移は決定的に保ちたい |
spec / declarative test |
10 ~ 30 |
仕様の補足だが,まだ人間が責任を持つべき |
impl / wiring |
60 ~ 100 |
制約が明確なら Agent にかなり委ねられる |
この数値に厳密な意味はない.
大事なのは,共通言語として「def は下げる」「impl は上げてよい」と話せることだ.
Agenty を 0 に近づけるべき場所
最初に強く言いたいのは,一般的なコーディングルールやプラクティスは,できる限り静的解析で決定的に行われるべき だということだ.
ここは高い Agenty を求める場所ではない.
むしろ 0 に近づけるべき場所である.
たとえば,
formatter による整形
lint rule による構文・規約チェック
型検査による不整合の検出
import 境界や依存方向の制約
exhaustiveness check や到達不能状態の検出
こうしたものは,本来 repo 自身が 機械的に拒否 できるべきだ.
ここを自然言語の運用に逃がしてはいけない.
AGENTS.md や Skills に「こういう書き方をしてね」と書くこと自体は補助として有効だが,それを repo の法にしてはいけない.
なぜなら,自然言語ベースの運用は本質的に非決定的だからだ.
モデルが変わる
プロンプトが少し変わる
文脈窓の入り方で解釈が変わる
Skill の適用順や読み取り方で結果が揺れる
つまり,そこに repo の invariant を預けると,ルールそのものが確率的になる.
それは Agenty を上げているのではない. 単に,守るべき境界を曖昧にしているだけだ.
私の感覚では,Skills は repo の真理を記述する場所ではなく,repo に埋め込まれた真理に Agent を従わせるための補助輪 である. 真理そのものは,なるべく静的な層に落ちていなければならない.
静的解析はドメインモデリングでもある
静的解析というと ESLint や formatter の話だけを思い浮かべがちだが,実際にはもっと広い. ドメインモデリングも type level に現れる.
つまり,
まず static なレイヤに定義を書く
その次に宣言的テストで補足する
実装は最後に置く
という順番が重要になる.
ここでいう「定義」は,単なる型エイリアスではない.
状態空間
イベント
遷移
入出力契約
エラーの表現
依存境界
こうしたものを,なるべく実装より手前に書いておく.
私はこの順番をかなり重視している. 先に実装を書き始めると,人間も Agent も,たいてい「いま書きやすいコード」の方向へ流される. しかし先に定義を置いておけば,実装はその contract を満たす作業に下がる.
この「実装を最後に追いやる」ことこそが,高い Agenty を安全に使う前提になる.
SDD に似て見えて,少し違う
ここまでの話は,一見すると SDD, つまり仕様駆動開発にかなり近く見えるかもしれない. 実際,「仕様を先に置く」「実装の前に合意を作る」という方向性そのものは近い.
ただ,私はそのまま同一視はしていない. 理由は単純で,運用面で必要な解像度が違う からだ.
現実の repo 運用では,曖昧な自然言語仕様をそのまま master にするのは無理がある. 人間同士の設計議論や RFC には自然言語が必要だし,それ自体は大切だ. しかし,自然言語はどうしても,
解釈の幅が広い
境界条件が抜けやすい
参照時に読み手の経験へ依存しやすい
Agent に読ませたときに確率的に揺れやすい
という性質を持つ.
だから私は,「自然言語仕様を起点にする」のではなく,自然言語の議論を,最終的に def や spec へ落とし切る ことを重視したい.
言い換えると,
RFC や議論は自然言語でよい
しかし repo の master は,できる限り形式的であるべき
ということだ.
仕様を自然言語のまま神棚に置くのではなく,型,状態遷移,宣言的テスト,静的制約へ変換する. そこまでやって初めて,Agent と人間の両方が同じ contract を参照できるようになる.
私はここが重要だと思っている. SDD が悪いというより,Coding Agent 時代には,自然言語だけをマスターにした仕様駆動では足りない. 確率的で曖昧な自然言語表現を repo の最終的な真理として運用するのは,現実世界では厳しい. だからこそ,Agenty の議論では「仕様を先に書く」だけでなく,「仕様をどこまで形式に落とすか」まで含めて考える必要がある.
def / spec / impl は framework に依存しない
fuckin-strict-nuxt-dmmf の面白いところは,*.def.ts と *.impl.ts を分けている点そのものより,分ける基準が framework ではなく責務になっている 点にある.
重要なのは「Vue だからこう分ける」ではない. むしろ,React でも Svelte でも server-side application でも,考え方は同じでよい.
たとえば,抽象化すると次のような分割になる.
feature/
order.def.ts
order.spec.ts
order.impl.ts
あるいは言語に依存しない記法なら,
feature/
order.def.*
order.spec.*
order.impl.*
と考えてもよい.
そしてそれぞれの意味は,おおむね次のようになる.
def: 低 Agenty.変更には設計意図が伴う.Agent にむやみに触らせないspec: 低から中 Agenty.受け入れ条件や宣言的シナリオを補足するimpl: 高 Agenty.制約の中で最も自由度が高く,Agent の探索空間になる
この分離があると,指示も運用も明確になる.
「
defは明示的な設計変更があるときだけ触る」「
specを満たすようにimplを直す」「レビューでは
defの diff を仕様変更として読む」「
implの diff は仕様充足として読む」
ここで初めて,Agenty が repo のトポロジに変換される.
Agenty は教育のフレームでもある
ここで強調しておきたいのは,この話は単なる repo 設計や Agent 運用の話ではない,ということだ. 人材教育のフレーム としても読める.
正直に言えば,def を必要十分に書き起こすのは難しい.
それは簡単な仕事ではない.
何が状態なのか
何がイベントなのか
どこまでを同一視し,どこで場合分けするのか
何を禁止状態として表現すべきか
どの境界を static に固定すべきか
こうしたことを,実装に逃げずに形式的に書くのは,かなり訓練が要る.
だが,私はそれでよいと思っている. むしろ そうあるべき だと思っている.
なぜなら,実装より先にドメイン仕様を形式的に表現する力こそが,これからの時代により重要になるからだ. Coding Agent が強くなるほど,「速く書く」ことの希少性は下がる. その代わりに,
何を定義すべきか
どこまでを機械に委ねてよいか
どの contract なら安全に自動化できるか
生成された実装が仕様を満たしているか
を見極める力の価値が上がる.
この意味で,def を書く練習は,単なる前処理ではない.
ドメインを形式化する筋力そのものを鍛える.
これは別にまったく新しい話ではない. 「実装をする前に RFC を書きましょう」「実装する前に設計をディスカッションしましょう」という従来の動きにかなり近い. ただ,Coding Agent の登場によって,この順序の意味がさらに強くなっただけだ.
以前は,設計を雑に始めても,最終的には人間が実装の泥臭さの中で辻褄を合わせることが多かった.
しかし Agent が大量の実装を高速に吐けるようになると,手前の定義の雑さが後段で増幅される.
だからこそ,先に def を議論し,spec を固めることの教育的価値が上がる.
私は,Coding Agent の登場によって「後続人をどう育成するのか」という議論はたちまち話題になっている,少なくともそうなりつつあると思っている. もし実装の大部分を Agent が書くなら,若い開発者は何を学べばよいのか,という問いである.
このフレームは,その解決策の一つになりうる.
まず
defを書くspecで受け入れ条件を明確にするimplは Agent と一緒に作る生成物を contract と diff でレビューする
こうすると,育成の焦点は単なるタイピング速度や暗記量ではなく,
ドメインの切り分け
境界の設計
状態遷移の記述
仕様の言語化
生成物の検証
へ移る.
私はこれは健全だと思う.
実装力が不要になるわけではない.
むしろ,良い def や spec を書くには実装感覚も必要だ.
ただ,育成の順序が変わる.
まず実装から入るのではなく,先に仕様を記述し,その後に実装を読む・直す・評価する 方向へ重心が移る.
そしてこのやり方は,個人の学習だけでなく,組織運用としてもサステナブルだ.
知識が「ベテランの頭の中」や「うまくいった prompt の言い回し」ではなく,def や spec という static な資産として repo に蓄積されるからだ.
これは教育にも,保守にも,引き継ぎにも効く.
高い Agenty を本当に求めるべき場所
では,どこに高い Agenty を置くべきなのか.
私は,複数の実装がありえて,しかも正しさを後段で機械的に検証できる場所 だと思っている.
具体的には,
mapping
adapter
UI wiring
API client の組み立て
view と state の接着
boilerplate が多い domain implementation
のような場所だ.
これらは「やり方」は複数あるが,「満たすべき条件」は比較的明確に書ける. だから,先に contract と spec を固定しておけば,実装側の Agenty はかなり高くできる.
逆に,次のような場所で高い Agenty を求めると危ない.
state machine そのもの
business rule の例外条件
境界値や禁止状態の定義
architectural boundary
repo 全体の coding rule
ここは「あとで直せばよい」では済まない. ここが揺れると,それ以降のすべての自動化が不安定になる.
Web フロントエンドでは VM を def に書き起こす
Web フロントエンドでは,この話は特に重要になる.
私は MVVM 的な分離をいま一度強く見直すべきだと思っている. ただし関心があるのは「ViewModel というクラスを作ること」ではない. VM レイヤの状態遷移を,実装の前に定義として書き起こすこと に関心がある.
たとえば,
export type CheckoutState =
| { kind: "Idle"; cart: Cart }
| { kind: "Submitting"; cart: Cart }
| { kind: "Succeeded"; orderId: OrderId }
| { kind: "Failed"; cart: Cart; reason: CheckoutError };
export type CheckoutEvent =
| { type: "Submit" }
| { type: "Resolve"; orderId: OrderId }
| { type: "Reject"; reason: CheckoutError };
export type Transition = (state: CheckoutState, event: CheckoutEvent) => CheckoutState;
こういうものは checkout.vm.def.ts のような場所にあるべきだ.
ここで固定したいのは UI の見た目ではない. 画面がどういう状態を持ち,どういうイベントでどこへ遷移するか である.
この層は低 Agenty にしておくべきだ. なぜなら,これはそのままプロダクトの振る舞いだからだ.
一方で,
状態から props への写像
component の分割
event handler の wiring
副作用の実装
といった部分は,契約が定義されていればより高い Agenty を許容できる.
ただしここで注意したいのは,MVVM の V に相当する部分は,まだ AI による制御がそんなに簡単ではない ということだ.
layout, typography, spacing, motion, visual hierarchy のような領域は,単に state contract があれば自動で良くなるわけではない.
ここは state machine の正しさとは別種の難しさを持っている.
むしろ V は,状態管理の延長として扱うよりも,デザインツールと統合されるべき別のソース・オブ・トゥルース として考えた方がよい.
たとえば,
画面状態と遷移は
VM defに書く受け入れ条件は
VM specに書く見た目やレイアウトは design tool 側で管理する
実装コードはその両者を接続する
という分離である.
この意味では,Web フロントエンドの Agenty は単純に一本の軸ではない. 少なくとも,
VM: 低 Agenty な定義と,高 Agenty な実装に分離しやすいV: まだ AI 単体では制御しづらく,design system / design tool との統合が重要
という違いがある.
だから私は,Web フロントエンドでは
VM defは低 AgentyVM specは中 AgentyVM implは高 AgentyViewは state 管理とは別軸で,design tool と接続して扱う
と整理するのがよいと思っている.
これをやっておくと,プロダクトの振る舞いは repo 側の VM で握りつつ,V はより適切な design workflow に委ねられる.
つまり,画面の意味論と画面の造形を,無理に同じ場所へ押し込めなくてよくなる.
これは運用とレビューのしやすさにも直結する
この設計は,単に AI-friendly というだけではない. 実際にソースコードを運用するうえで効いてくる.
まず,仕様の分離 が効く.
def と spec が手前にあると,「何を変えたかったのか」と「どう実現したか」が diff 上で分離される.
次に,Agent による改変のしやすさ が上がる.
編集可能領域を impl に寄せられるので,プロンプトは単純になる.
「この契約を守って実装して」と言える.
さらに,コードレビューのしやすさ が上がる. レビューアは全 diff を同じ粒度で読まなくてよくなる.
defが変わっているなら仕様レビューspecが変わっているなら期待値レビューimplだけなら実装レビュー
というふうに,読むモードを切り替えられる.
高い Agenty を扱う時代ほど,この diff の意味論が重要になる. なぜなら,Agent は大量のコードを書けるが,人間のレビュー帯域はほとんど増えないからだ.
だからこそ,人間が本当に読むべき差分は,できるだけ静的で,宣言的で,小さく保たれていなければならない. そして,その静的で宣言的な差分こそが,教育可能で,引き継ぎ可能で,組織的にもサステナブルな資産になる.
結
Agenty という言葉で言いたいのは,単に「AI にどこまで任せるか」ではない. どこを確率的にしてよく,どこを決定的に固定すべきか という設計の話である.
一般的なルール,ドメインの境界,状態遷移,契約. これらはなるべく static に,type level に,そして機械的に検査できる形で置くべきだ. その上で,宣言的テストで仕様を補足する. 実装は最後に置く.
高い Agenty を求めるべき場所は,repo の法がすでに定まっていて,その範囲で自由に探索してよい場所だけである.
repo 全体を Agent に明け渡すのではない. Agent が暴れてよい sandbox を,architecture 側で先に作る.
私はこれが,これからの Coding Agent 時代の設計だと思っている.