Vibe Codingでそれなりの成果物を得るためには、設計、タスク分解、テスト戦略、コードレビュー、リファクタリング指示などを適切に行う必要がある、という話を前に書いた。AIに身を委ねて感覚でコーディングするVibe Codingは、理想的には「こんなものを、いい感じで」と頼むだけでコードができあがる夢の開発環境を指すのだろう。
しかし現実はそう甘くない。AIは私たちの心を読めるわけではなく、「いい感じ」の指示では意図通りに動かない。明確なビジョンとしっかりした設計に基づき、AIが理解できる言葉でタスクを分解して伝える必要がある。
そこで今回は、その実践としてソリティアのアイデア発想から実装までをLLMに任せてみた。ソリティアといってもWindowsについてくるアレ(いわゆるクロンダイク)ではなくて、一人で遊べるトランプゲームのことだ。例えば、こんなゲームがVibe Codingで作れる。
実装した結果のリポジトリは以下になる。
こういったものを作る上で、どのような工夫が必要だったかを記録しておく。
設計
まず、LLMとの対話の取っ掛かりとして、「ソリティアを定義するための型や関数をTypeScriptで設計する」ことから始めた。結果として、ゲームの状態(GameState)やプレイヤーのアクション(Action)の型、そしてゲーム初期化(setupGame)、可能なアクションリスト取得(getAvailableActions)、アクション適用(applyAction)、ゲーム終了判定(checkGameEnd)といった関数を含む汎用的なソースコードのひな型が得られた。これを基に個別のゲームルールを定義していく。
タスク分解
ソリティア実装までのフェイズをあらかじめ設定し、LLMに伝える。具体的には、コンセプト定義 → ルール詳細化・定義 → ルールレビュー → ルールのシミュレーション評価 → ルール改善 → テストの設計・実装 → ビューの実装 → 入力ハンドリング → チュートリアル機能実装、という流れだ。これらのフェイズをプロンプトで順次指定することで、AIが一度に抱えるタスクを限定し、迷走を防ぐ。
テストと実装の順番は悩ましい。最初のソリティア開発では、手探りだったため実装を先行させ、後追いでテストを設計した。しかしその経験から、次のソリティアでは最初にルール定義部分のテストケース群をLLMに書かせ、それをパスするように実装を進めるTDD的なアプローチを試した。初期段階で設計の妥当性を検証でき、手戻りを減らす効果があったように思う。何もない状態からのTDDは難しいかもしれないが、一度成功例があれば、それを基にテストを先行させる方が効率が良いかもしれない。
テスト戦略
テスト戦略は2つに分かれる。一つはゲームルールの破綻を防ぐ「シミュレーション」、もう一つはコード自体の破綻を防ぐ「テストケース群」だ。
シミュレーションは、設計フェーズで定義したルール記述のソースコードを用いる。プレイヤー動作を模擬する簡単なAIロジックを実装し、多数回ゲームを自動実行して勝率や詰みパターンを確認する。極端なバランスのゲームは要調整だ。ソリティアを選んだのは、このシミュレーションとバランス調整が比較的容易だからだ。プレイヤーの行動は明確で模擬しやすく、調整も手札数や勝利条件の変更など分かりやすい。
コードに対するテストケース群は、通常のユニットテストに近い。今回はルール定義部分がシミュレーションで実質的にテストされているため、ビュー描画や入力ハンドリングといった周辺部分が主対象だ。Jestを使い、外部ライブラリの動作はモック関数で代替した。E2Eテストほどの網羅性はないが、手軽さで十分な安心感が得られる。
このようなテストを用意しておくことである程度の安心感が得られる。AIコーディングエージェントは元のコードの動作を破壊してしまうことがままある。しかもVibe Codingではエージェントが生成したコードを人間がまともに見ないので、それらの破壊は静かに行われる。気づいたころにはメタメタにされたコードベースが残されてしまう。そういった事態を防ぐのにテストはとても役立つ。
ただ、そのテスト自体もLLMに書かせている場合、テストコードが間違っていたら元も子もない。初期段階やコア部分のテストは人間が注意深くレビューし、妥当性を確認する必要がある。そうなると純粋なVibe Codingとは言えないかもしれない。結局、AIが書いたコードの品質を見極め、的確な指示を出す人間の目と手が必要とされる。
コードレビュー、リファクタリング指示
LLMに指示を重ねてコードを拡充すると、単一関数に機能が雪だるま式に追加され、見通しが悪くなることがある。その際は「この機能を別関数に切り出して」といったリファクタリング指示を行い、可読性と保守性を保つ必要がある。今回の例では、ゲームルール定義とシミュレーションAI、ゲーム本体処理とチュートリアル制御などが混在していたのを、それぞれ別ファイルや関数に分離・整理した。
このような開発プロセスを支えるプロンプト自体も、LLMに相談しながら作成している部分がある。「新しいソリティアゲームを開発したいが、そのステップを一緒に考えてほしい」といった対話から始め、固まったプロセスや指示内容を汎用的なプロンプトとして整形していく。これを繰り返す。
これがVibe Codingかと言われると、少し違う気もする。
一般的なVibe Codingは、単一の小さなツールをサッと作る用途を想定しているように思う。対して今回行ったのは、様々なソリティアを効率的かつ品質を保って生成する「仕組み」自体をLLMと共に設計・構築する、いわばメタプログラミング的な取り組みだ。LLMが気持ちよく的確に「バイブスでコーディング」できるお膳立てを人間が行う。なので残念ながら人間にはバイブスは無い。
こういった「Meta Vibe Coding」とでも呼ぶべきアプローチは、人間にとって決して楽ではない。むしろ、従来のプログラミング以上に設計能力、問題発見能力、そしてLLMとの高度なコミュニケーション能力が要求される。しかし一度この「仕組み」を実装すれば、同じ枠組みで類似のものを――今回の例なら新しいソリティア――を比較的容易かつ高速に実装できる可能性がある。これがLLM時代の開発の新しい側面かもしれない。
生成AIの進化で単純なコーディング作業は不要になるかもしれない。代わりに人間には「AIにどう賢く働いてもらうか」を設計し、環境を整備する「メタなレベル」の活動が求められる。そして、このメタレベルもいずれAIに取って代わられ、人間はさらにそのメタな視点へとシフトしていく。そんな連鎖が続くと仮定した場合、コーディングというタスクにおいて最終的に人間に残される役割とは何だろうか。
それはおそらく、「何を作るべきか」という問いそのものを定義する力、つまり解決すべき真の課題を発見し、そのための独創的なコンセプトやアイデアを生み出すこと、あたりだろうか。未知の領域に対する探求心や、人間ならではの美的感覚・感性を反映したユーザーエクスペリエンスの創造、なぜそれを作るのかという目的意識、この辺をAIが身に着けることはまだ難しい、はず。ただ、こういったまだAIには難しいであろうが次々に覆されていくのが昨今なので、数年後どうなっているかは分からん。人間ごときがバイブスを語ってんじゃねーよ、という世界もあるかもしらん。