AIエージェントが当たり前になったいま、エンジニアの仕事は少し様変わりして、「どう作るか」よりも、「どう指示するか」が重要になってきました。
AIはとても優秀な部下。しかし、ちょっぴり受け身で「指示待ち人間」な部下です。
指示の出し方が下手だと、プロジェクトは思った通りに進みません。
世の中にはAIツールの性能比較記事が溢れています。
ただ、同じAIでも指示の仕方次第でアウトプットがまったく違うという視点での実証はあまり見つかりません。
そこで今回は、指示の粒度を変えてAIにUIを作らせ、その差を見てみます。
丸投げすると暴走するかもしれませんし、指示を丁寧に出すと忠実に動くかもしれません。
さらに最終的には、最近話題の「仕様駆動開発」まで試してみます。
AIに仕様書を書かせ、それをもとにコーディングさせると、果たしてどれだけのものが仕上がるのか。
正直、部下として優秀すぎて嫉妬するかもしれませんが、そのあたりも含めて検証します。
今回は大規模言語モデルとして、VSCode上で GitHub Copilot + Claude Sonnet 4 を使用します。
ポイントは「同じAIに、指示の出し方だけを変えて比較する」ことです。
ブラウザ上ですぐに動作確認できるものがよいので、フロントエンドのみで簡単な カンバン方式のTodoリストのUI を作ってみようと思います。
技術スタックは HTML + TailwindCSS + JS を基本要件とします。
「Todoリスト」というワードからイメージするものに世間的な共通認識があるので、全く違うものが出てくるということはないはずです。
まず最初は技術要件も伝えず、とにかくざっくり丸投げして作ってもらいましょう。
プロンプトはこんな感じです。
使いやすいTodoリストアプリのUIモックを作成します。 UI/UXはモダンで高品質なものを望みます。 サンプルでいくつかダミーのタスクを登録しておいてほしいです。
丸投げです。ほぼ「任せた!」状態ですね。
特に「モダンで高品質な」という要望はいい具合にフワッとしているのではないでしょうか。
さすがClaude、全体的にはちゃんと「Todoアプリ」の体裁になっていますが、いくつか気になる点があります。
やはりというか「モダンで高品質な」という抽象的なオーダーの解釈に苦慮したようで、グラデーションにグラデーションを重ねた背景が見づらいですね。
また、ドラッグによる並び替えが出来なかったり、登録したタスクの編集が出来なかったり、実装というより仕様定義の甘さが見られます。(私が指示しなかったのが悪いのですが)
とはいえ、ほんの数分でこれが上がってくるのだから、手の速さはもはや人間と比べるべくもないです。
次は、具体的な要件を列挙してみました。
ブラウザ上で動作するPC向けのToDoリストUIを作成します。 以下の要件に基づき、UIを実装してください。 * 使用技術:HTML、TailwindCSS、JavaScript * 対応環境:PC / モダンブラウザ(Chrome、Safari、Edge最新版) * カンバン方式で一覧性のあるUI * カテゴリー(カンバンの列)は以下の3種類。わかりやすく色分けする。 * ToDo * 進行中 * 完了 * タスクの項目 * タイトル(必須) * 詳細(任意) * 優先度(任意) * 期日(任意、日付形式) * タスクの操作 * 新規登録(追加) * 削除 * 完了(「完了」列への移動) * 各ボード内の「+」ボタン押下でタスクの新規登録が可能 * UI上でタスクのカテゴリー間の移動ができる(ドラッグ&ドロップまたはボタン操作) * サンプルとして、ダミーのタスクをいくつか初期表示しておく * レスポンシブ対応は不要(PC向けのみ) * データ保存は不要(リロードで初期化されてOK)
要件をすべてドキュメントとして伝えたことで、欲しい機能を満たすものが出てきました。
また、「カンバン方式」という明確なUIイメージを伝えたことで、UI設計の完成度が上がっています。
丸投げverより見た目も機能も改善。
指示の粒度が上がると、AIの出力も自然と精度が上がります。
ここからは本番です。まずAIに以下の指示を出します。
使いやすいTodoリストアプリのUIモックを作成します。 UI/UXはモダンで高品質なものを望みます。 仕様を検討して、spec.mdファイルに詳細な仕様書としてまとめてください。 UI/UX要件と機能要件を分けて記述し、できるだけ詳細に定義してください。
お気づきでしょうか、前半部分は最初の「丸投げver」とまったく一緒の内容です。
このフワッとしたオーダーを、「仕様書」として定義し直してもらおうと思います。
仕様書を作るところからスタートする、いわゆる「仕様駆動開発」です。
都度AIと壁打ちしながら完成させていく バイブコーディング に対し、はじめにAIに指示する内容の精度を高めてから一気に完成させるのが 仕様駆動開発(Spec-Driven Development) 。
はたして曖昧だった指示は、どのような「仕様」に落とし込まれるでしょうか。
# カンバン方式Todoリストアプリ UI仕様書 ## 概要 使いやすく、モダンなUI/UXを備えたカンバン方式のTodoリストアプリのUIをHTML・TailwindCSS・JavaScriptで実装する。 ## UI/UX要件 - ### レイアウト - 3つ以上のカンバン列(例:ToDo/進行中/完了)を横並びで表示 - 各列はカード型で、ドラッグ&ドロップでタスク移動可能 - レスポンシブ対応(PC・タブレット・スマホ) - ヘッダーにアプリ名・テーマ切替(ライト/ダーク)ボタンを配置 - 新規タスク追加ボタンは各列上部に設置 - ### ビジュアル - TailwindCSSによるモダンなデザイン - カードや列にシャドウ・角丸・ホバー効果 - 状態ごとに色分け(例:ToDo=青、進行中=黄、完了=緑) - アニメーション(ドラッグ時、追加・削除時のフェード/スライド) - ### ユーザビリティ - タスク編集はインラインで可能(ダブルクリックやアイコンから) - 削除・アーカイブ機能(確認ダイアログあり) - 検索・フィルタ(キーワード、状態、期限など) - タスク詳細表示(モーダルまたはサイドパネル) - 操作ガイド・ツールチップ表示 --- ## 機能要件 - ### タスク管理 - タスク追加・編集・削除 - タスクのドラッグ&ドロップによる状態変更 - タスクにタイトル・説明・期限・優先度・ラベル・担当者(任意)を設定 - タスク詳細表示・編集 - タスクのアーカイブ・復元 - ### カンバン列管理 - 列の追加・編集・削除(初期は3列) - 列名変更 - 列の並び替え - ### データ保存 - ローカルストレージによる永続化 - 必要に応じて外部API連携(オプション) - ### その他 - 検索・フィルタ機能 - 操作履歴(アンドゥ/リドゥ) - 初回利用時のチュートリアル表示 --- ## 技術要件 - HTML5, TailwindCSS, JavaScript(ES6+) - モジュール構造(可読性・保守性重視) - サンプルとしていくつかダミーデータを配置する
UI/UX要件・仕様要件・技術要件をそれぞれ具体化してくれました。
ここからが重要なところですが、この仕様書をしっかりレビューして、必要に応じて欲しい機能を追加したり、要望と違うところは修正したりして、仕様書の完成度を上げておくという作業が必要です。
例えば、こんな要件を追加しようと思います。
ということで以下の内容をspec.mdに追記しました。
## 機能要件 - ### その他 - テーマ切替(ライト/ダーク)
## 技術要件 - 必要に応じて外部ライブラリを使用(例:SortableJS, dayjs, Heroicons等)
最後に、作った仕様書を基にコーディングさせます。
仕様書(spec.md)に従って、TodoアプリのUIを実装してください。
ついに求めるものが完成形で出てきました。
機能的に網羅されている上、追加要望としたダークモードも追加されて、かなり洗練されたUIになっています。
並び替えはsortablejsライブラリを使用することで効率化してくれました。
完成されたインプット(仕様書)からは、完成されたアウトプット(成果物)が得られる。
UIとしての完成度の差はブラウザ上で確認できましたが、コードとしての完成度はどうでしょうか。
私は不精なので、コードレビューもAIにお願いすることにします。
それぞれのバージョンのhtmlとjsについて、 以下の観点から評価し、レポートしてください。 ・コードの読みやすさ ・保守性 ・拡張性
出力されたレポートの抜粋がこちら。
## 総合比較 | 評価項目 | 仕様駆動 | 丸投げ | 要件リスト | |---------|------|----------|-----------| | 読みやすさ | A+ | B+ | C+ | | 保守性 | A | B | D+ | | 拡張性 | A | B- | D | | **総合** | **A** | **B** | **D+** | ### 仕様駆動 - **そのまま使用推奨** - 企業レベルの開発に適用可能 - TypeScript化でさらなる品質向上が期待できる ### 丸投げ - **改善後使用推奨** - データ永続化機能の追加が急務 - エラーハンドリングの強化が必要 ### 要件リスト - **大幅リファクタリング必要** - クラスベース設計への移行 - グローバル変数の排除 - データ永続化とエラーハンドリングの実装 ## 結論 **仕様駆動** のコードが最も優秀で、実際のプロダクション環境でも使用できる品質です。 **丸投げ** は基本的な品質は保たれているものの改善の余地があり、 **要件リスト** は学習目的としては良いものの、実用には大幅な改修が必要です。
「仕様駆動」のコード品質が高いのは予想通りで、仕様書に明記された「モジュール構造(可読性・保守性重視)」の要件が効いていると思われます。
が、意外なことに、「丸投げ」よりも「要件リスト」の評価が悪いです。
実際にコードを見てみても、行き当たりばったりにfunctionが追加されており、確かに保守性が高いとは言えないものでした。
class KanbanApp { constructor() { this.tasks = []; this.currentTaskId = null; this.searchTerm = ''; // DOMの初期化 this.initializeDOM(); // イベントリスナーの設定 this.setupEventListeners(); // ドラッグ&ドロップの初期化 this.initializeSortable(); // データの読み込み this.loadData(); // テーマの初期化 this.initializeTheme(); // dayjsの設定 dayjs.locale('ja'); dayjs.extend(dayjs_plugin_relativeTime); } initializeDOM() { this.elements = { searchInput: document.getElementById('searchInput'), themeToggle: document.getElementById('themeToggle'), taskModal: document.getElementById('taskModal'), confirmDialog: document.getElementById('confirmDialog'), taskForm: document.getElementById('taskForm'), modalTitle: document.getElementById('modalTitle'), closeModal: document.getElementById('closeModal'), cancelTask: document.getElementById('cancelTask'), confirmCancel: document.getElementById('confirmCancel'), confirmOk: document.getElementById('confirmOk'), confirmMessage: document.getElementById('confirmMessage'), taskTitle: document.getElementById('taskTitle'), taskDescription: document.getElementById('taskDescription'), taskPriority: document.getElementById('taskPriority'), taskDueDate: document.getElementById('taskDueDate'), taskLabels: document.getElementById('taskLabels'), kanbanBoard: document.getElementById('kanbanBoard') }; }
信頼できそうな書き出し
// タスクデータを管理する配列 let tasks = []; let taskIdCounter = 1; let currentCategory = ''; // 初期化 document.addEventListener('DOMContentLoaded', function() { initializeSampleData(); renderAllTasks(); }); // サンプルデータの初期化 function initializeSampleData() { tasks = [ { id: taskIdCounter++, title: 'デザインの確認', detail: 'クライアントからのフィードバックを反映', priority: 'high', dueDate: '2025-09-28', category: 'todo', completed: false }, { id: taskIdCounter++, title: 'コーディング作業', detail: 'フロントエンドの実装を進める', priority: 'medium', dueDate: '2025-09-30', category: 'progress', completed: false }, { id: taskIdCounter++, title: '資料作成', detail: '提案書の作成完了', priority: 'low', dueDate: '2025-09-25', category: 'completed', completed: true } ]; } // モーダルを開く function openAddTaskModal(category) { currentCategory = category; document.getElementById('addTaskModal').classList.remove('hidden'); document.getElementById('addTaskModal').classList.add('flex'); document.getElementById('taskTitle').focus(); }
この部下はちょっと計画性がなさそうだぞ
これは、かえって丸投げしてしまえばAIは世間に公開されているコードの「最大公約数」を出力するため、結果的に一般論として良いとされている実装に収斂するが、中途半端に要件を追加するとその「最大公約数」が取りづらくなるのではないかと。
つまり、半端に要件を入力するくらいなら、一度仕様書に落としてから実装させたほうが結果として手数が少なくなる という結論に至ります。
AIエージェントのアウトプットを左右するのはツールの性能ではなく、人間の指示の出し方だということが今回の検証であらためて実証できました。
丸投げすればそれなり、要件を細かく並べれば忠実、仕様書に落とせば一気に完成度アップ。
部下や同僚に「とりあえずやっといて」と言うか、「手順書読んでやって」と言うか、「設計書渡して頼む」と言うかの違いだと思えば、当然の話です。
ただ、人間相手に丸投げを繰り返したら嫌われてしまいますが、AI相手だと文句も言わずにすぐやってくれるので、どんどん指示が雑になること、あると思います。
急がば回れ。
でもAI相手なら、「急がば仕様書を回せ」が正解かもしれません。