これまで、ハーネス(CLAUDE.md、skill、settings.json など)を育てる話を、何度か書いてきました。今回は、もう少し広い視点で── コードベースや規約そのものが、AI に対するハーネスになっている、という話を考えてみます。

AIも人間も、周辺コードを真似する

AI にコードを書かせると、周辺のコードを真似します。既存のパターン、命名、構造に倣う。これは、ある意味で良いことです。一貫性が保たれるから。

でも、これは人間も同じです。新しくチームに入ったエンジニアは、既存のコードを見て、「このプロジェクトは、こう書くのか」と倣う。周辺コードが、暗黙のお手本になる。

つまり、コードベースそのものが、お手本(ハーネス)になっている。AI も人間も、それを参照して、次のコードを書く。

ここに、良し悪しがあります。お手本が良ければ、良いコードが増える。お手本が悪ければ、悪いコードが増える。

シニアの判断力 ── 真似しない選択

シニアエンジニアは、周辺コードを見て、「これは古いパターンだから、倣わない」「もっと良い書き方がある」と、判断できます。真似する/しないを、選べる。

でも、AI は、これが苦手です。周辺コードを、無批判に真似しがち。「このパターンは、実は良くない」という判断は、文脈とドメインを要する。AI は、目の前のパターンを、お手本として倣ってしまう。

これは、ジュニアにも近いところがあります。ジュニアも、最初は周辺コードを無批判に真似する。経験を積んで、「これは倣うべき、これは倣うべきでない」と、判断できるようになる。その真似しない選択が、シニアの判断力。

ダメなパターンの増殖 ── AI slop 化

AI が、周辺の「良くないパターン」を真似すると、同じパターンが増殖します。一つの良くない書き方が、AI によって、コードベース中にコピーされていく。

前に「AI slop」という言葉に触れました。AI が大量生成した、質の低いコンテンツ。コードベースでも、これが起きる。良くないパターンが、AI によって増殖し、コードベースが slop 化していく

しかも、これは観測しにくい。一つ一つは「動く」コードだから。レビューでも、「既存パターンに倣っている」と見えるので、通りやすい。気がつくと、良くないパターンが、コードベース中に広がっている。

「人間が分かり難いものは、AI も分かり難い」── 良くないパターンが増えると、人間も AI も、読みにくくなる。負のスパイラル。

具体例: サービスクラスの call

具体例を挙げます。Rails で、サービスクラスを call メソッドだけで統一する規約があります。

class CreateOrder
  def call
    # 注文を作成する処理
  end
end

これ自体は、悪くない。インターフェースが統一されて、分かりやすい。

でも、これが行き過ぎると、問題が出ます。call 一つに、責務が集まりすぎる。本来、複数のメソッドに分けるべき処理が、call の中に詰め込まれる。あるいは、「call だけ」の規約を守るために、クラスが大量に生産される。一つの処理を、いくつもの小さなサービスクラスに分割して、それぞれ call を持たせる。

AI は、この規約を見て、忠実に call を量産します。「call だけ」というパターンを、無批判に倣う。結果、責務過多の call や、細かすぎるサービスクラスが、増えていく。

規約は、良かれと思って作られる。でも、AI がそれを忠実に量産すると、規約の弊害も増幅される。

DRY し過ぎは、人間にもAIにも分かりにくい

よくあるのが DRY のし過ぎです。
DRY(Don’t Repeat Yourself)── 重複を避ける。良い原則です。でも、行き過ぎると、問題になる。

例えば、scope をチェーンしまくったコード。一つ一つは小さく共通化されているが、解体しないと、全体で何をしているか把握できない。命名から推測しようにも、命名が長く複雑になるし、そもそも命名が正しい保証もない(実装と命名がずれていることもある)。一箇所を直すと、思わぬところに影響する。抽象化が深すぎて、意図が読めない。

これも、「人間が分かり難いものは、AI も分かり難い」。過度に DRY なコードは、AI に渡しても、文脈を読み違える。

「いつ DRY するか、いつ重複を許すか」は、シニアの判断です。重複が、たまたま同じになっているだけなら、無理に共通化しない。本質的に同じものだけ、共通化する。この取捨選択の判断が、難しい。AI は、「重複してるから共通化」と、機械的に DRY しがち。

規約と現実のギャップ

ここで、難しい問題があります。規約と、現実のコードには、ギャップがある

例えば、「サービスクラスは call のみ」という規約があるとします。でも、現実には、例外がある。規約を決めた本人が、意図を持って、call 以外のメソッドを使っていたりする。「ここは、こういう理由で、規約から外れている」という、コメント付きで。

すると、AI は、どちらを真似すべきか、分からない。規約通りの call のみのクラスを真似するか、例外的に複数メソッドを持つクラスを真似するか。
プロジェクトによっても違います。プロジェクトA は「call のみ」が徹底されている。プロジェクトB は、複数メソッドも許容している。AI は、どのプロジェクトのパターンを、お手本にすべきか。

つまり、規約が明文化されていても、現実とのギャップがあると、AI は迷う(人間も迷う)。「規約上はこうだが、現実はこう」という暗黙の了解は、AI には伝わりにくい。

リファクタの優先順位 ── 先に払うか、後で払うか

良くないパターンや、規約とのギャップに気付いたとき、「いつ直すか」という判断があります。

先に払う: 気付いた時点で、リファクタする。コストは今かかるが、負債が溜まらない。
後で払う: 今は動いているので、放置する。コストは後回しだが、負債が溜まる(利子がつく)。

AI で書くコストが下がると、「先に払う」が、やりやすくなります。リファクタのコストが下がるから。気付いた時点で、AI と一緒に直す。

ただし、リファクタには、リスクもあります。動いているものを変えると、壊れるかもしれない。だから、テストで挙動を固定してから(前回の記事で書いた話)。そして、「いつ、何を、どこまで」直すかは、人間の判断。AI は、自分から「リファクタしましょう」とは言わない。

規約は、少ない方がいい

規約が多いと、まず認知負荷が上がる。全部を把握しておく必要があるが、多いと忘れる。規約同士に矛盾があると、「どっちに従えばいいか」で止まる。レビューでも、「規約ではこうだが」と議論になる。そして、AI も、規約が多いと忘れることがある。人間も AI も、多すぎる規約は、抱えきれない。

そもそも、規約が少ない方がいいのは、昔からの話です。Rails の「設定より規約(Convention over Configuration)」が、いい例です。フレームワークが規約を持っているから、プロジェクト固有の規約が少なくて済む。Rails way を知っていれば、プロジェクトに入って、すぐ成果を出せる。

これは、AI 時代に、さらに効く気がします。AI は、Rails way のような広く知られた規約を、学習しています。でも、プロジェクト固有の規約は、知らない(学習データにない)。だから、プロジェクト固有の規約を増やすほど、AI も人間も、学習コストが上がる。広く知られた規約に乗り、プロジェクト固有の規約は最小限にする方が、人間にも AI にも、効く。

例えば、命名規約。これは、AI 時代には、不要かもしれません。AI の方が、名付けのセンスがあることも多い。そもそも、命名の良さは、本質ではない。動くか、保守できるか、の方が本質です。

ここで、冒頭の話に戻ります。AI も人間も、周辺コードを真似する。だとすれば、規約をたくさん書くより、お手本になるコードを良くする方が、効く。コードが良ければ、真似されるのも良いコード。良くないパターンが増殖するなら、規約を増やすのではなく、お手本のコードをリファクタする。規約という「言葉」より、コードという「実例」の方が、AI にも人間にも、伝わりやすい。

それに、AI は、規約(文字)を、必ずしも守らない。何度か書いてきた「地頭が良く自信過剰な新人」── AI は、迷って立ち止まるより、自信過剰で進むことが多い。「規約ではこうだが」と確認するより、確信を持って書いてしまう。だから、文字の規約に頼るより、AI が出力したコードを見て、評価する方が、確実です。コードを見れば、認識違いが具体的に分かる。文字のやり取りで「これでいい?」と確認するより、コードで判断する方が、正しく評価できる。

ここまでは Rails の例で書きましたが、これは Rails に限った話ではありません。DDD(ドメイン駆動設計)やクリーンアーキテクチャも、ある意味、「広く知られた規約」です。Entity、Repository、Use Case、依存方向のルール── 用語や層がたくさんあって、規約が多いように見えるかもしれません。でも、これらは広く知られているので、AI も学習している。プロジェクトで独自の設計を作るより、こうした既存の設計思想に乗る方が、人間にも AI にも、伝わりやすい。

ただし、ここでも、「広く知られた」のは概念のレベルです。Entity や Repository の定義は、AI も知っている。でも、自分のプロジェクトでどう適用するか── どこを Entity にするか、Repository をどこに置くか、Aggregate の境界をどう引くか── は、プロジェクトごとに違う。これは、コードで示す(お手本コード)、あるいはドメインを理解した人間が判断する領域です。AI が知っているのは概念、適用は人間とコードで示す、と捉えると、整理しやすい。

そして、規模に見合うかの判断も大事です。DDD やクリーンアーキテクチャは、ボイラープレートが多くなりがち。複雑なドメインで価値が出ますが、小さなアプリには過剰なことも多い。「広く知られた規約だから採用する」のではなく、自分のプロジェクトに見合うかで判断する。ここでも、規約は最小限から、というスタンスは変わりません。

とはいえ、規約がゼロになるわけではありません。どうしても必要な規約は、残る。そのときは、パスごとに分割する手もあります。Claude Code には、.claude/rules/ というディレクトリがあり、ルールを複数のファイルに分けて、関連するパスを触るときだけ、読み込ませることができます。Model のルール、Spec のルール、と分けておけば、Model を触るときに、Spec のルールまで読み込まずに済む。「規約が多いと、認知負荷が上がる」問題への、一つの緩和策です。

ただ、注意したいのは、「分割できるから、規約を増やしていい」わけではないということ。まず、規約は少なく。お手本コードで示せるものは、コードで。その上で、どうしても必要な規約だけ、パスで分けて整理する。順番は、「減らす」が先です。

つまり、規約をたくさん書くより、広く知られた規約に乗り、コードで示せるものはコードで示し、AI の出力はコードを見て評価する。規約は、少ないほどいい。これも、AI 時代に特有の話ではなく、昔から良いとされてきたことが、より効くようになった、という気がします。

まとめ

コードベースと規約を、ハーネスとして考えてみました。

  • AI も人間も、周辺コードを真似する。コードベースが、暗黙のお手本(ハーネス)
  • シニアは「真似しない選択」ができる。AI は、無批判に真似しがち
  • 良くないパターンが、AI によって増殖し、コードベースが slop 化する
  • 具体例: サービスクラスの call の量産、DRY のし過ぎ(scope チェーンなど)── 行き過ぎると、人間にもAIにも分かりにくい
  • 規約と現実には、ギャップがある。AI は、どちらを真似すべきか迷う
  • リファクタは、先に払うか、後で払うか。AI でコストが下がると、先に払いやすい
  • 規約は、少ない方がいい。昔からの話(Rails way)で、AI 時代にさらに効く
  • DDD やクリーンアーキテクチャも、広く知られた規約。概念は AI も知っているが、適用はプロジェクトごと。規模に見合うか判断する
  • 規約(文字)より、お手本コード。AI は自信過剰で文字を守らないので、コードを見て評価する
  • どうしても必要な規約は、.claude/rules/ のようにパスで分割。ただし、減らすが先

コードベースも、規約も、放っておくと、AI によって良くないパターンが増殖する。だから、規約を増やすのではなく、お手本のコードを良くする。規約は少なく、広く知られた規約に乗る。これも、いつものエンジニアリングの延長── 昔から良いとされてきたことが、AI で増殖のスピードが速いぶん、より効くようになった気がします。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です