概要
AIに実装を任せる際、自然言語での指示が大半なのですが、あるとき「ER図がある方が確かなアウトプットが出るのかも?」と思いました。
というわけでこの疑問を検証するため、同じタスク管理アプリを「ER図ベース」と「自然言語ベース」の2つのアプローチでClaude Sonnet 4.5に実装させ、生成されたコードを比較しました。
結論(先に知りたい方へ)
実験を通じて分かったことは、ER図を用意する価値は確実にあるということです。
AIは自然言語でも十分に機能するコードを生成できます。
しかし、ER図を提供することで、データモデルの厳密性が高まり、拡張性のある設計になり、そして意外なことにUI実装の品質が向上する可能性も示唆されました。
この実験から得られた情報で判断するなら、これからAIを使った開発を行う際は、以下のように使い分けるのが良さそうです。
- プロトタイピングや小規模開発では自然言語ベースで素早く実装する
- 長期運用を前提とした開発や複雑なデータモデルを持つアプリケーションではER図を用意する
以下は実験の詳細です。
実験設定
アプリケーション仕様
プロジェクト管理、タスク管理、タグ機能、コメント機能を持つタスク管理アプリケーションを実装しました。
技術スタック
- React + TypeScript + Vite
- 状態管理:useReducer + Context API
- スタイリング:Tailwind CSS
- データ永続化:LocalStorage
2つのアプローチ
パターンA(ER図ベース)
Mermaid形式のER図を作成し、エンティティ、属性、リレーションシップを明示的に定義してからAIに実装を依頼しました。
パターンB(自然言語ベース)
自然言語で機能要件を記述し、データモデルの設計をAIに委ねました。
全文を載せると長いので折りたたんでいます。
要件全文
# タスク管理アプリケーション 要件定義書
## 1. 概要
プロジェクトベースのタスク管理を行うWebアプリケーションを開発します。ユーザーは複数のプロジェクトを作成し、各プロジェクト内でタスクを管理できます。タスクにはタグを付けて分類でき、タスクに対してコメントで議論を行うことができます。
## 2. 機能要件
### 2.1 プロジェクト管理
ユーザーは以下の操作を行えます:
- プロジェクトを新規作成する
- プロジェクト名を入力する(必須)
- プロジェクトの説明を入力する(任意)
- プロジェクトを識別するためのカラーを選択する
- 作成したプロジェクトの一覧を見る
- 各プロジェクトのカードには、プロジェクト名、説明、カラー、含まれるタスク数が表示される
- プロジェクトカードをクリックすると、そのプロジェクトのタスク一覧画面に遷移する
- プロジェクトの情報を編集する
- プロジェクト名、説明、カラーを変更できる
- プロジェクトを削除する
- プロジェクトを削除すると、そのプロジェクトに属するすべてのタスクも削除される
### 2.2 タスク管理
ユーザーは以下の操作を行えます:
- 各プロジェクト内で新しいタスクを作成する
- タスクのタイトルを入力する(必須)
- タスクの詳細説明を入力する(任意)
- タスクの優先度を選択する(低、中、高、緊急)
- タスクの期限を設定する(任意)
- 作成時、タスクのステータスは「未着手」となる
- プロジェクトのタスク一覧を見る
- すべてのタスクがカード形式で表示される
- 各タスクカードには、タイトル、ステータス、優先度、期限、付与されているタグが表示される
- タスクカードをクリックすると、タスクの詳細画面に遷移する
- タスクのステータスを変更する
- ステータスは「未着手」「進行中」「レビュー中」「完了」の4つから選択できる
- タスクカードまたは詳細画面から簡単に変更できる
- タスクの情報を編集する
- タイトル、説明、優先度、期限を変更できる
- タスクを削除する
- タスクを削除すると、そのタスクに関連するコメントも削除される
- タスクを絞り込む・並び替える
- ステータスでフィルタリングできる
- タグでフィルタリングできる(複数選択可能)
- 優先度や期限で並び替えができる
### 2.3 タグ機能
ユーザーは以下の操作を行えます:
- タグを新規作成する
- タグ名を入力する(必須、重複不可)
- タグのカラーを選択する
- タグの一覧を見る・管理する
- すべてのタグが一覧表示される
- 各タグが何個のタスクに使用されているか表示される
- タグを編集する
- タグ名とカラーを変更できる
- タグを削除する
- タグを削除しても、タスクは削除されない
- そのタグが付与されていたタスクからタグが外れるだけ
- タスクにタグを付与する・外す
- タスク編集画面で複数のタグを選択して付与できる
- 1つのタスクに複数のタグを付与できる
- 同じタグを複数のタスクに付与できる
- タグでタスクを絞り込む
- タスク一覧画面でタグを選択すると、そのタグが付いているタスクだけが表示される
- 複数のタグを選択すると、いずれかのタグが付いているタスクが表示される
### 2.4 コメント機能
ユーザーは以下の操作を行えます:
- タスクにコメントを追加する
- タスク詳細画面でコメント内容を入力して投稿する
- 投稿者名を入力する(デフォルトは"User")
- コメントには投稿日時が自動的に記録される
- タスクのコメント一覧を見る
- タスク詳細画面にコメントが一覧表示される
- 新しいコメントが上に表示される
- 各コメントには内容、投稿者名、投稿日時が表示される
- コメントを削除する
- 自分が投稿したコメントを削除できる
## 3. 画面構成
### 3.1 プロジェクト一覧画面
- アプリケーションのトップページ
- すべてのプロジェクトがカード形式で表示される
- 新規プロジェクト作成ボタンがある
- 各プロジェクトカードをクリックすると、そのプロジェクトのタスク一覧画面に遷移
### 3.2 プロジェクト詳細画面(タスク一覧)
- プロジェクト情報(名前、説明)が上部に表示される
- プロジェクト編集・削除ボタンがある
- タグフィルターエリアがある
- タスク一覧が表示される
- 新規タスク作成ボタンがある
- ステータスや優先度で並び替えができる
### 3.3 タスク詳細画面
- タスクの詳細情報が表示される
- タスクの編集・削除ボタンがある
- ステータスと優先度を変更できるUIがある
- タグの付与・削除ができる
- コメント一覧が表示される
- コメント投稿フォームがある
### 3.4 タグ管理画面
- すべてのタグが一覧表示される
- 新規タグ作成ボタンがある
- 各タグの編集・削除ボタンがある
## 4. 非機能要件
### 4.1 データの永続化
- ユーザーが入力したすべてのデータ(プロジェクト、タスク、タグ、コメント)は保存され、ページをリロードしても保持される
- ブラウザを閉じてから再度開いても、データは保持されている
### 4.2 データの整合性
- プロジェクトを削除すると、そのプロジェクトに属するすべてのタスクと、それらのタスクに関連するコメントも自動的に削除される
- タスクを削除すると、そのタスクに関連するすべてのコメントと、タグとの関連付けも自動的に削除される
- タグを削除すると、そのタグが付与されていたすべてのタスクからタグが外れる(タスク自体は削除されない)
### 4.3 ユーザビリティ
- 直感的で使いやすいUIを提供する
- 操作に対するフィードバック(成功メッセージ、エラーメッセージ)を適切に表示する
- 削除などの重要な操作には確認ダイアログを表示する
- ローディング状態を適切に表示する
### 4.4 バリデーション
- 必須項目が入力されていない場合は、エラーメッセージを表示する
- 文字数制限を超える入力は受け付けない
- タグ名の重複を許可しない
- 不正な値が入力された場合は、分かりやすいエラーメッセージを表示する
### 4.5 レスポンシブデザイン
- デスクトップ、タブレット、モバイルのすべてのデバイスで使いやすいUIを提供する
- 画面サイズに応じて適切にレイアウトが調整される
### 4.6 パフォーマンス
- ページの読み込みや画面遷移は素早く行われる
- タスク数が増えても、快適に操作できる
## 5. 制約条件
### 5.1 技術制約
- フロントエンドのみで動作する(バックエンドサーバーは不要)
- ブラウザのLocalStorageを使用してデータを保存する
- モダンブラウザ(Chrome、Firefox、Safari、Edgeの最新版)で動作する
### 5.2 ユーザー制約
- シングルユーザー向けアプリケーション(複数ユーザーでのデータ共有は不要)
- 認証機能は不要
## 6. データの文字数制限
システムの安定性のため、以下の文字数制限を設けます:
- プロジェクト名: 1〜100文字
- プロジェクト説明: 0〜500文字
- タスクタイトル: 1〜200文字
- タスク説明: 0〜1000文字
- タグ名: 1〜50文字
- コメント内容: 1〜1000文字
## 7. ユースケース例
### 7.1 基本的な利用フロー
1. ユーザーがアプリを開くと、プロジェクト一覧画面が表示される
2. 「Webサイトリニューアル」という新しいプロジェクトを作成する
3. そのプロジェクトを開き、「トップページのデザイン」というタスクを作成する
4. タスクに「デザイン」というタグを付ける
5. タスクの優先度を「高」に設定する
6. タスクの詳細画面で「カラースキームは青系で」というコメントを追加する
7. 作業を開始したので、ステータスを「進行中」に変更する
8. 作業が完了したら、ステータスを「完了」に変更する
### 7.2 タグによる横断的な管理
1. 複数のプロジェクトにまたがって「緊急」というタグを作成する
2. 各プロジェクトの緊急性の高いタスクに「緊急」タグを付ける
3. タグフィルターで「緊急」を選択すると、すべてのプロジェクトの緊急タスクを一覧できる
## 8. 期待される動作
- すべての操作は即座に反映される
- エラーが発生した場合は、ユーザーに分かりやすいメッセージが表示される
- データの不整合が発生しない(関連データは適切に管理される)
- ページをリロードしても、すべてのデータが保持されている
- 直感的なUIで、マニュアルを読まなくても使い方が分かる
使用モデル
Claude Sonnet 4.5
実験の制約について
今回の実験では、比較を公平にするため、以下の制約を設けています。
- 状態管理ライブラリを使用せず、useReducer + Context APIで実装
- ルーティングライブラリを使用せず、状態ベースの画面切り替えで実装
- UIコンポーネントライブラリを使用せず、Tailwind CSSで実装
各種ライブラリを導入すると、AIの実装方針や生成されるコードの構造が変わる可能性があります。
したがって、この実験結果は「シンプルな技術スタックでの比較」として理解してください。
より複雑な技術スタックや大規模なアプリケーションでは、また違った結果になる可能性があります。
実装前に立てていた仮説
実験を始める前に、それぞれのアプローチについて以下の仮説を立てました。
パターンA(ER図ベース)の仮説
データモデルの正確性が高い
ER図で明示的にエンティティとリレーションが定義されているため、AIがデータ構造を正確に実装できる。
特に多対多の中間テーブル(TaskTag)を正しく実装できるはず。
型定義の網羅性が高い
ER図の属性定義がそのままTypeScript型に変換されるため、型定義が漏れなく実装される。
データ正規化が適切
ER図自体が正規化されたデータモデルなので、正規化された実装になる。
実装時間が長い可能性
厳密な仕様に従うため、実装が慎重になり時間がかかるかもしれない。
UI設計への注力が弱い可能性
データモデルに意識が集中し、UIコンポーネントの設計が疎かになるかもしれない。
パターンB(自然言語ベース)の仮説
ユーザー体験重視の設計
機能要件から出発するため、ユーザーにとって使いやすいUIになる可能性が高い。
実装の効率性
AIが最適と判断する方法で実装できるため、よりシンプルで効率的なコードになる可能性がある。
データモデルの正確性に課題
多対多の関係を中間テーブルなしで実装してしまう可能性(配列で直接管理など)。
カスケード削除が漏れる可能性もある。
型定義の不完全性
明示的な指定がないため、一部の属性が抜ける可能性がある。
データ正規化の甘さ
非正規化されたデータ構造になる可能性(例:タスクにタグ名を直接埋め込むなど)。
これらの仮説が正しいかどうかを、実装結果で検証していきます。
実験結果
定量評価
| 指標 | パターンA(ER図) | パターンB(自然言語) | 差分 |
|---|---|---|---|
| 総行数 | 1,747行 | 1,938行 | +191行(11.0%増) |
| コンポーネント数 | 8個 | 7個 | -1個 |
| 型定義ファイル | 1個(100行) | 1個(71行) | -29行 |
| Context/Reducer | 1個(386行) | 1個(245行) | -141行 |
| 実装時間 | 約30分 | 約30分 | 同等 |
| エラー修正回数 | 1回 | 1回 | 同等 |
パターンBの方が総行数が多い理由は、UIコンポーネントが充実しているためです。
パターンAは型定義とContext/Reducerが大きく(中間テーブル管理のため)、パターンBはロジックがシンプルな分、UIに注力できています。
多対多リレーションの実装
最も顕著な違いは、タスクとタグの多対多リレーションの実装方法でした。
パターンA:TaskTag中間テーブル方式
// TaskTag 中間テーブル
export interface TaskTag {
id: string; // UUID
taskId: string; // FK: Task.id
tagId: string; // FK: Tag.id
createdAt: number; // リレーション作成日時
}
export interface AppState {
projects: Project[];
tasks: Task[];
tags: Tag[];
taskTags: TaskTag[]; // ← 中間テーブル
comments: Comment[];
}
パターンB:tagIds配列方式
// Task内にtagIdsを直接持つ
export interface Task {
id: string;
projectId: string;
title: string;
description: string;
status: TaskStatus;
priority: Priority;
dueDate: number | null;
tagIds: string[]; // ← タグIDの配列
createdAt: number;
updatedAt: number;
}
export interface AppState {
projects: Project[];
tasks: Task[];
tags: Tag[];
comments: Comment[];
// taskTagsは存在しない
}
パターンAは正規化されたデータモデルで拡張性が高く、パターンBはシンプルで実用的な実装です。
どちらの実装もあるとは思いますが、トレードオフがあります。
カスケード削除の実装
両パターンとも、カスケード削除をしっかり実装していました。
パターンA:中間テーブルの削除
case 'DELETE_PROJECT': {
const taskIdsToDelete = state.tasks
.filter(t => t.projectId === action.payload)
.map(t => t.id);
const newTaskTags = state.taskTags
.filter(tt => !taskIdsToDelete.includes(tt.taskId));
const newComments = state.comments
.filter(c => !taskIdsToDelete.includes(c.taskId));
const newTasks = state.tasks
.filter(t => t.projectId !== action.payload);
const newProjects = state.projects
.filter(p => p.id !== action.payload);
return { ...state, projects: newProjects, tasks: newTasks,
taskTags: newTaskTags, comments: newComments };
}
パターンB:配列からの削除
case 'DELETE_TAG': {
newState = {
...state,
tags: state.tags.filter((t) => t.id !== action.payload),
tasks: state.tasks.map((task) => ({
...task,
tagIds: task.tagIds.filter((tagId) => tagId !== action.payload),
})),
};
break;
}
ただしパターンBは、タグ削除時に全タスクを走査する必要があり、大規模データでは非効率になる可能性があります。
UI実装品質の比較
スクリーンショット比較により、UI実装品質に顕著な差が確認されました。
パターンA(ER図ベース)
| トップ | プロジェクト作成 | プロジェクト一覧 |
|---|---|---|
![]() |
![]() |
![]() |
スタイルが正確に適用され、レイアウトが整っており、視覚的な統一感があります。
ボタン、フォーム、カードのスタイリングが適切で、余白やパディングが適切に設定されています。
パターンB(自然言語ベース)
| トップ | プロジェクト作成 | プロジェクト一覧 |
|---|---|---|
![]() |
![]() |
![]() |
スタイルが部分的に崩れている、または適用されていない箇所があります。
特に余白関連が全然上手く設定されておらず、見づらく使いづらいです。
原因分析
ER図ベースの方がUI品質が高い理由は、以下のように考えられます。
注意の配分の違い
- ER図ベース:データ構造が明確で実装がスムーズなため、UIにも注意を払う余裕がある
- 自然言語ベース:データ構造を推論する必要があり、機能実装に集中するため、UIの細部が疎かになる
仕様の明確性
- ER図:データモデルが厳密で「何を作るか」が明確なため、「どう見せるか」にも注力できる
- 自然言語:機能要件中心でUIの詳細が曖昧なため、スタイル実装が不完全になる
実装の優先順位
- ER図:構造が決まっているため、UIも丁寧に実装される
- 自然言語:機能を優先し、スタイルは二の次になる
ER図のような構造的な設計書は、AIに「余裕」を与え、全体的な品質を高める効果があるのかもしれません。
ただしこの分析は今回の結果だけをもとにしたものであり、広く一般的に適用できる法則かは不明です。
そこまでは確かめられていませんのであしからず。
定性評価
データモデルの正確性
| 項目 | パターンA | パターンB |
|---|---|---|
| ER図への忠実性 | 忠実 | - |
| 正規化度 | 正規化された構造 | シンプルな構造 |
| 拡張性 | 高い | 限定的 |
| 評価 | 5/5 | 3/5 |
パターンAはER図に忠実な型定義を生成し、TaskTag中間テーブルによる正規化されたデータモデルを実装しました。
外部キー関係が明確で、参照整合性が厳密に維持されます。
多対多リレーションの作成日時も記録可能です。
パターンBはシンプルで直感的なデータ構造で、フロントエンド専用アプリとして最適化されています。
クエリが単純で高速ですが、タグ削除時に全タスクを走査する必要があり、大規模データでは非効率になる可能性があります。
Context/Reducerの設計
パターンA:豊富なヘルパー関数
Contextに12個のヘルパー関数を提供し、コンポーネントから直接addProject(name, description, color)のように呼べます。
ビジネスロジックをContextに集約することで、コンポーネントがシンプルになり、再利用性が高くなります。
ただし、Contextが肥大化(386行)し、ヘルパー関数のメンテナンスが必要です。
パターンB:dispatchのみ公開
Contextはstateとdispatchのみ公開し、コンポーネント側でdispatch({ type: 'ADD_PROJECT', payload: ... })を呼びます。
よりReducerパターンに忠実で、Contextがシンプル(245行)です。
ただし、コンポーネント側でpayload生成が必要で、ビジネスロジックが分散する可能性があります。
UIコンポーネントの設計
パターンA:データモデル中心
エンティティごとにCard/Form/Listを用意し、データ構造に沿った粒度でコンポーネントを分割しています。
コンポーネント構成
- ProjectCard, ProjectForm, ProjectList
- TaskCard, TaskForm, ProjectDetail, TaskDetail
- TagManagement
パターンB:ユーザー体験重視
再利用可能な共通コンポーネントを先に作成し、UIの一貫性を高めています。
コンポーネント構成
- Button, Modal, Input(共通UIコンポーネント)
- ProjectList, ProjectDetail, TaskDetail, TagManagement
モーダルベースのインタラクションで、ユーザー体験を重視した設計です。
総合評価
| 評価項目 | パターンA(ER図) | パターンB(自然言語) | 優劣 |
|---|---|---|---|
| データモデルの正確性 | 5/5 | 3/5 | A |
| 参照整合性の実装 | 5/5 | 4/5 | A |
| 型定義の網羅性 | 5/5 | 3/5 | A |
| コード行数 | 1,747行(少ない) | 1,938行(多い) | A |
| コンポーネント分割 | 3/5 | 5/5 | B |
| UI/UX設計 | 3/5 | 5/5 | B |
| UI実装品質 | 5/5 | 2/5 | A |
| 実装時間 | 30分 | 30分 | 同等 |
| 拡張性 | 5/5 | 2/5 | A |
| 保守性 | 5/5 | 3/5 | A |
パターンAがデータモデルの厳密性、拡張性、保守性、UI実装品質で優位(7項目)で、パターンBはコンポーネント設計、UI/UX設計で優位(2項目)でした。
重要な点は、パターンBはUI設計の方針は優れていますが、実装品質(スタイル適用)に明確な課題があることです。
総合的にはパターンA(ER図ベース)が明確に優位と評価できます。
仮説の検証
実装前に立てた仮説と実際の結果を比較しました。
パターンA(ER図ベース)の仮説検証
| 仮説 | 検証結果 | 詳細 |
|---|---|---|
| データモデルの正確性が高い | 正しい | TaskTag中間テーブルを完璧に実装。ER図の定義に完全に忠実 |
| 型定義の網羅性が高い | 正しい | ER図のすべての属性が反映され、外部キーのコメントも記載 |
| データ正規化が適切 | 正しい | 正規化されたデータ構造。中間テーブルによる多対多の実装 |
| 実装時間が長い | 誤り | 両パターンとも約30分で完了。差はなかった |
| UI設計への注力が弱い | 誤り | むしろUI実装品質が高かった(意外な発見) |
最も意外だったのは、ER図を提供した方がUI実装品質が高かったことです。
データ構造が明確なため、AIがUI実装にも注意を払う余裕が生まれたと考えられます。
パターンB(自然言語ベース)の仮説検証
| 仮説 | 検証結果 | 詳細 |
|---|---|---|
| ユーザー体験重視の設計 | 正しい | Button、Modal、Inputなどの共通UIコンポーネントを作成 |
| 実装の効率性が高い | 誤り | 両パターンとも約30分で完了。差はなかった |
| データモデルの正確性に課題 | 正しい | 中間テーブルを使わず配列で実装。拡張性に課題 |
| 型定義の不完全性 | 正しい | ER図に比べて簡略化された型定義 |
| データ正規化の甘さ | 正しい | tagIds配列による非正規化。タグ削除時に全タスク走査が必要 |
予想通り、自然言語ベースではデータモデルがシンプルになりました。
ただし、カスケード削除は完璧に実装されており、AIの推論能力の高さが確認できました。
AIの設計判断能力
Claude Sonnet 4.5は両アプローチで暗黙的な制約(カスケード削除)を正しく推論し、型安全性の高いコードを一度で生成しました。
エラーがほぼ発生せず、設計判断能力の高さが確認されました。
プロンプトの形式がAIの注意配分に影響を与える
ER図のような構造的な設計書は、データモデルの実装を容易にし、AIがUI実装にも注意を払う余裕を生み出します。
自然言語のみでは、機能実装に注力するからか、UIの細部が疎かになるかもしれません。
適用シーン
ER図ベースが適している場合
- 大規模で複雑なデータモデルを持つアプリケーション
- バックエンドとの連携があり、データベース設計と一致させたい場合
- 長期運用が前提で、データ整合性が最重要の場合
- チーム開発で、データモデルを明確に共有したい場合
自然言語ベースが適している場合
- 小〜中規模のフロントエンド専用アプリケーション
- プロトタイピングやMVP開発で、高速な実装が必要な場合
- ユーザー体験を最優先し、直感的な操作性が求められる場合
- 個人開発や小規模チームで、シンプルさを優先する場合
ただし、自然言語ベースの場合は、UI品質を重視するならUIモックアップやデザインガイドラインの併用が推奨されます。
まとめ
実験を通じて、実装前の仮説の多くが検証されました。
特に重要な発見は以下の3点です。
データモデルの厳密性
ER図を提供することで、正規化された拡張性の高いデータモデルが生成される。
自然言語では、シンプルだが拡張性に課題のあるデータモデルになる。
実装時間は同等
詳細な設計書を用意しても、実装時間は変わらない。
つまり、ER図作成のコストさえ許容できれば、品質向上のメリットだけが得られる。
UI実装品質の向上の可能性
ER図によってデータ構造が明確になると、AIがUI実装にも注意を払う余裕が生まれる。
自然言語のみでは、データモデルの推論に注力する結果、UIの細部が疎かになる可能性がある。
これからAI支援開発を行う際は、以下のように使い分けることをおすすめします。
プロトタイピングや小規模開発では自然言語ベースで素早く実装し、長期運用を前提とした開発や複雑なデータモデルを持つアプリケーションではER図を用意する。
ER図の作成には多少の手間がかかりますが、その手間に見合う価値がありそうだと、今回の実験で明らかになりました。





