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に現れる

つまり,

1.まずstaticなレイヤに定義を書く2.その次に宣言的テストで補足する3.実装は最後に置く

という順番が重要になる.

ここでいう「定義」は,単なる型エイリアスではない.

  • 状態空間

  • イベント

  • 遷移

  • 入出力契約

  • エラーの表現

  • 依存境界

こうしたものを,なるべく実装より手前に書いておく.

私はこの順番をかなり重視している. 先に実装を書き始めると,人間もAgentも,たいてい「いま書きやすいコード」の方向へ流される. しかし先に定義を置いておけば,実装はそのcontractを満たす作業に下がる.

この「実装を最後に追いやる」ことこそが,高いAgentyを安全に使う前提になる.

SDDに似て見えて,少し違う

ここまでの話は,一見するとSDD, つまり仕様駆動開発にかなり近く見えるかもしれない. 実際,「仕様を先に置く」「実装の前に合意を作る」という方向性そのものは近い.

ただ,私はそのまま同一視はしていない. 理由は単純で,運用面で必要な解像度が違う からだ.

現実のrepo運用では,曖昧な自然言語仕様をそのままmasterにするのは無理がある. 人間同士の設計議論やRFCには自然言語が必要だし,それ自体は大切だ. しかし,自然言語はどうしても,

  • 解釈の幅が広い

  • 境界条件が抜けやすい

  • 参照時に読み手の経験へ依存しやすい

  • Agentに読ませたときに確率的に揺れやすい

という性質を持つ.

だから私は,「自然言語仕様を起点にする」のではなく,自然言語の議論を,最終的にdefspecへ落とし切る ことを重視したい. 言い換えると,

  • 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でレビューする

こうすると,育成の焦点は単なるタイピング速度や暗記量ではなく,

  • ドメインの切り分け

  • 境界の設計

  • 状態遷移の記述

  • 仕様の言語化

  • 生成物の検証

へ移る.

私はこれは健全だと思う. 実装力が不要になるわけではない. むしろ,良いdefspecを書くには実装感覚も必要だ. ただ,育成の順序が変わる. まず実装から入るのではなく,先に仕様を記述し,その後に実装を読む・直す・評価する 方向へ重心が移る.

そしてこのやり方は,個人の学習だけでなく,組織運用としてもサステナブルだ. 知識が「ベテランの頭の中」や「うまくいったpromptの言い回し」ではなく,defspecという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は低Agenty

  • VM specは中Agenty

  • VM implは高Agenty

  • Viewはstate管理とは別軸で,design toolと接続して扱う

と整理するのがよいと思っている.

これをやっておくと,プロダクトの振る舞いはrepo側のVMで握りつつ,Vはより適切なdesign workflowに委ねられる. つまり,画面の意味論と画面の造形を,無理に同じ場所へ押し込めなくてよくなる.

これは運用とレビューのしやすさにも直結する

この設計は,単にAI-friendlyというだけではない. 実際にソースコードを運用するうえで効いてくる.

まず,仕様の分離 が効く. defspecが手前にあると,「何を変えたかったのか」と「どう実現したか」がdiff上で分離される.

次に,Agentによる改変のしやすさ が上がる. 編集可能領域をimplに寄せられるので,プロンプトは単純になる. 「この契約を守って実装して」と言える.

さらに,コードレビューのしやすさ が上がる. レビューアは全diffを同じ粒度で読まなくてよくなる.

  • defが変わっているなら仕様レビュー

  • specが変わっているなら期待値レビュー

  • implだけなら実装レビュー

というふうに,読むモードを切り替えられる.

高いAgentyを扱う時代ほど,このdiffの意味論が重要になる. なぜなら,Agentは大量のコードを書けるが,人間のレビュー帯域はほとんど増えないからだ.

だからこそ,人間が本当に読むべき差分は,できるだけ静的で,宣言的で,小さく保たれていなければならない. そして,その静的で宣言的な差分こそが,教育可能で,引き継ぎ可能で,組織的にもサステナブルな資産になる.

Agentyという言葉で言いたいのは,単に「AIにどこまで任せるか」ではない. どこを確率的にしてよく,どこを決定的に固定すべきか という設計の話である.

一般的なルール,ドメインの境界,状態遷移,契約. これらはなるべくstaticに,type levelに,そして機械的に検査できる形で置くべきだ. その上で,宣言的テストで仕様を補足する. 実装は最後に置く.

高いAgentyを求めるべき場所は,repoの法がすでに定まっていて,その範囲で自由に探索してよい場所だけである.

repo全体をAgentに明け渡すのではない. Agentが暴れてよいsandboxを,architecture側で先に作る

私はこれが,これからのCoding Agent時代の設計だと思っている.