ChatGPT、GitHub Copilot、Cursor、そしてその類のツールは、プロンプトを打ち終える前にReactコンポーネントを吐き出せるようになっています。Next.jsのルートをSupabaseに接続する?数秒で完了です。絡まったTypeScriptのユーティリティをリファクタリングする?型ガードを備えた3つの選択肢を提示してくれます。モダンなウェブスタックで働くすべての人にとって、その体験は魔法に近いものに感じられるかもしれません。

私はこれらのツールを毎日使っています。私のスタックはNext.js、TypeScript、そしてSupabaseです。AIはエディタの中に常駐し、カスタムフックの雛形作成、データベースクエリの生成、あるいは乱雑な条件分岐の整理をいつでもこなしてくれます。小規模なタスクにおいては、非常に優秀で足の速いジュニアデベロッパーのように振る舞います。構文を完璧に把握しており、Googleで検索しなければならないAPIの仕様も記憶しています。ボイラープレートを書くことに飽きることもありません。

しかし、ソフトウェアは壊れ続けています。アプリは遅くなり、カスタマーダッシュボードはラグが発生し、エッジケースによってフォームがクラッシュします。AIによってコーディングがこれほど容易になったのに、なぜソフトウェアを使う感覚は数年前よりも悪化しているのでしょうか?

その答えは、「構文を生成すること」と「ソフトウェアを構築すること」は、全く別の仕事だからです。

構文はアーキテクチャではない

AIはトークンの扱いに非常に長けています。SupabaseのリアルタイムチャネルをリッスンするuseEffectフックを書いてと頼めば、コンパイル可能なコードが返ってきます。型のないJavaScriptファイルを厳格なTypeScriptに変換したり、コーヒーを飲む前にZodバリデーションを備えたフォームコンポーネントを立ち上げたりすることも可能です。

しかし、AIにはアプリケーション固有の輪郭を理解することはできません。優れたソフトウェアには、意図的な状態管理、レースコンディションへの慎重な対処、そしてデータがどこに存在し、どこに単に表示されているのかという明確なマップが必要です。AIが見ているのは目の前のファイルであり、システム全体ではありません。AIはコードベースを、耐力壁を持つ生きた構造物としてではなく、平坦なテキストの回廊として扱ってしまうのです。

まるで、実際に家で暮らしたことのない建築家のようです。彼らは美しい間取り図を描くことができますし、寝室に窓がいくつ必要かも知っています。しかし、2月にどこで配管が漏れやすいか、あるいは夏の暑さでどの廊下が使い物にならなくなるかといったことは知りません。その「生活に基づいた知識」こそが、建物を維持させるのです。コードもそれと同じです。

2つの摩擦点

厳格なガードレールなしにAIに大きなコードの塊を書かせると、同じ2つの問題が繰り返し発生することに気づきます。

第一に、AIはすでに確立されているデザインパターンを無視します。例えば、チームですべてのデータフェッチを専用のカスタムフック層に抽出しているかもしれません。あるいは、SupabaseのRLSポリシーをフロントエンドのヘルパーにマッピングする方法について厳格な規約があるかもしれません。AIはそんなことは気にしません。プロンプトの要求を即座に解決するためなら、ボタンのonClickの中に生のsupabase.from().select()を放り込みます。コードは動きます。見た目も綺麗かもしれません。しかし、それはコードベースにおける「異物」であり、あらゆる異物は将来のリファクタリングという税金になります。半年後、誰かがその針を見つけ出し、なぜそれが存在するのかを理解し、そっと元の規律へと戻さなければならなくなるのです。

第二に、シンプルで済む場面で複雑さに手を伸ばします。AIツールは、抽象ファクトリや複雑なリデューサーパターン、多層的な高階コンポーネント(HOC)を必要とするような大規模なリポジトリで学習されています。単純な問い合わせフォームの作成を依頼したとしても、ステートマシン、コンテキストプロバイダー、そして3つのファイルにまたがるカスタムフックの抽象化を提示してくるかもしれません。その解決策は技術的に間違っているわけではありません。ただ、重すぎるのです。不必要なレイヤーが増えるたびに、認知的な負債が積み重なっていきます。作業をスキップしたのではなく、利息付きで先送りにしただけなのです。

ベロシティの罠

ここには危険なフィードバックループが存在します。AIによって機能構築のスピードは2倍になりますが、人間の注意力のスケールはそれと同じようにはいきません。開発スピードが2倍になったとき、コードレビューに費やす時間は2倍になっていますか?テストは増えていますか、それとも減っていますか?

実のところ、生成されたコードは「もっともらしく」見えるため、非常に簡単に信じ込んでしまいがちです。モダンな構文が使われ、コメントは適切な場所に散りばめられ、変数名もプロフェッショナルに聞こえます。しかし、その洗練された外見の中に、微妙なバグが潜んでいます。セッターを忘れたフックの依存関係配列。技術的には正しいが、考慮漏れのnull状態を許容してしまうTypeScriptの型。特定のスキーマにおける論理削除(soft-delete)された行を考慮し忘れたSupabaseのクエリ。納期のペースに追われ、一行ずつ読む代わりに、流し読みをしてしまいます。月曜日のスピード感は素晴らしいものです。しかし、金曜日のデバッグ作業は深夜まで続くことになるのです。

真のコスト

この代償を払わされるのは、開発者ではありません。エンドユーザーなのです。

ソフトウェアが使いにくく感じられるのは、チームが管理できるスピードよりも複雑さが速く増大しているからです。私たちは、無敵になったかのような錯覚を与えるツールを手に、より少人数のチームでより大規模なアプリケーションを構築しています。一人の開発者が午後のひとときでダッシュボード全体をスキャフォールディングできてしまうと、組織は水曜日までに3つのダッシュボードが出来上がることを期待します。配慮のないスケールアップは、脆弱なシステムを生み出します。ステートは膨張します。バンドルサイズは徐々に増大します。レースコンディションは増殖します。インターフェースはモダンに見えるかもしれませんが、ユーザーが戻るボタンを押すとリセットされたり、AIが生成したデータフェッチのウォーターフォールをプロファイリングする時間が誰もなかったために、ハイドレーションに4秒もかかったりします。

機械のために働くのではなく、機械と共に働く

これらは決して、エディタからAIを排除すべきだという意味ではありません。境界線が必要だという意味なのです。

AIが得意なことのために使いましょう。退屈な作業はAIに任せます:繰り返しの多い TypeScript インターフェース、Supabase クエリのボイラープレート、Jest のセットアップ