概要
kiroで仕様駆動開発を始めました。
仕様駆動開発において重要なのは、Specsとして与える仕様と、Steeringとして与えるプロジェクト固有のルール、コーディング規約、ベストプラクティスの指定です。
これらの良い書き方について、サンプルアプリケーションを作らせながら学んでみました。
実装内容
- TODOアプリ
- CRUD操作のみのシンプルなアプリケーション
- フロントエンド: React + TypeScript + Tailwind CSS
- バックエンド: Node.js + Express + TypeScript
- データベース: SQLite
- 機能: タスクの追加・一覧表示・ステータス切り替え・削除・フィルタリング
- AIモデル:Claude Sonnet 4.5
requirements.md
仕様駆動ではspecファイルに仕様を定義して、それを元に設計、タスク出し、実装をしてくれます。
まずは、TODOアプリの仕様を決めましょう。
ゼロから完璧な仕様書を考えるのは大変です。
必須の機能をChat GPTなどに伝えて適当な仕様書のベースを作ってもらいました。
# シンプルタスク管理アプリ (Simple Task Manager)
## 概要
個人のタスクを登録・管理できるシンプルなWebアプリケーション。
## 技術スタック
- フロントエンド: React + TypeScript
- バックエンド: Node.js + Express
- データベース: SQLite(ローカル開発用)
- スタイリング: Tailwind CSS
## 機能要件
### 1. タスク一覧表示
- 登録済みタスクを一覧で表示する
- 各タスクには「タイトル」「ステータス」「作成日時」を表示
- ステータスでフィルタリングできる(すべて / 未完了 / 完了)
### 2. タスク登録
- タイトル(必須、最大100文字)を入力してタスクを登録できる
- 登録時のステータスは「未完了」とする
- 作成日時は自動で記録される
### 3. タスク完了/未完了の切り替え
- タスクのステータスをワンクリックで切り替えられる
- 完了タスクは取り消し線で表示する
### 4. タスク削除
- 不要なタスクを削除できる
- 削除前に確認ダイアログを表示する
## API仕様
### エンドポイント一覧
| メソッド | パス | 説明 |
|---------|------|------|
| GET | /api/tasks | タスク一覧取得 |
| POST | /api/tasks | タスク登録 |
| PATCH | /api/tasks/:id | タスク更新(ステータス変更) |
| DELETE | /api/tasks/:id | タスク削除 |
### データモデル
typescript
interface Task {
id: number;
title: string;
completed: boolean;
createdAt: string; // ISO 8601形式
}
### リクエスト/レスポンス
#### GET /api/tasks
**レスポンス**
{
"tasks": [
{
"id": 1,
"title": "Kiroの記事を書く",
"completed": false,
"createdAt": "2025-01-15T10:30:00Z"
}
]
}
#### POST /api/tasks
**リクエスト**
{
"title": "新しいタスク"
}
**レスポンス**
{
"id": 2,
"title": "新しいタスク",
"completed": false,
"createdAt": "2025-01-15T11:00:00Z"
}
#### PATCH /api/tasks/:id
**リクエスト**
{
"completed": true
}
**レスポンス**
{
"id": 1,
"title": "Kiroの記事を書く",
"completed": true,
"createdAt": "2025-01-15T10:30:00Z"
}
#### DELETE /api/tasks/:id
**レスポンス**
{
"message": "Task deleted successfully"
}
## 画面仕様
### メイン画面レイアウト
┌─────────────────────────────────────┐
│ 📋 タスク管理 │
├─────────────────────────────────────┤
│ [________________] [追加] │
├─────────────────────────────────────┤
│ フィルター: [すべて] [未完了] [完了] │
├─────────────────────────────────────┤
│ ☐ Kiroの記事を書く 2025/01/15 │
│ [完了] [削除] │
│ ───────────────────────────────── │
│ ☑ 環境構築 2025/01/14 │
│ [未完了に戻す] [削除] │
└─────────────────────────────────────┘
### UI要素
- ヘッダー: アプリタイトル
- 入力エリア: テキストフィールド + 追加ボタン
- フィルターボタン: 3つのトグルボタン
- タスクリスト: タスクカードの縦並び
## 非機能要件
- レスポンシブ対応(モバイルでも操作可能)
- エラー時はユーザーにわかりやすいメッセージを表示
- 入力値のバリデーションをフロント・バック両方で実施
- 空文字のタスク登録は不可
これを元にフォーマットは気にせず仕様を書いていきましょう。
この状態の仕様書ではうまく仕様駆動開発をしてくれず、EARS形式で記述することが推奨されています。
Kiro は EARS(Easy Approach to Requirements Syntax)形式を使用した仕様の記述を支援します(例:システムは認証済みユーザーが有効な車のリストを閲覧できるようにしなければならない)。Kiro はこれらの要件からプロパティを抽出し、論理的にテスト可能なものを判断し、数百から数千のランダムなテストケースを生成してコードをチェックします。
出典:Kiro が一般提供開始: IDE とターミナルでチームと共に開発
初めからEARS形式で書くのは大変なので、自由なフォーマットで仕様をまとめてから完成後AIに変換してもらいましょう。
(一部抜粋)
#### 受入基準
1. WHEN ユーザーがアプリケーションを開いたとき、THE System SHALL すべてのタスクを一覧表示する
2. THE System SHALL 各タスクについてタイトル、ステータス、作成日時を表示する
3. WHEN ユーザーが「すべて」フィルターを選択したとき、THE System SHALL すべてのタスクを表示する
steering
必須ではありませんが、コーディング規約や制約などAIの動きをハンドリングできます。
まずは日本語で会話できるようにしましょう。今回はコード内のコメントも日本語にしてもらいます。
---
title: Language Rules
inclusion: always
---
# 言語設定 / Language Settings
## 出力言語 / Output Language
**すべての応答は日本語で行ってください。**
AIアシスタントは以下のルールに従う必要があります:
- すべての説明、コメント、ドキュメントは日本語で記述する
- コード内のコメントも日本語で記述する
- エラーメッセージや説明も日本語で提供する
- 技術用語は必要に応じて英語を併記してもよい(例:「プロパティ(property)」)
## 例外 / Exceptions
以下の場合は英語を使用してもよい:
- プログラミング言語のキーワードや構文
- 変数名、関数名、クラス名などの識別子
- 外部ライブラリやフレームワークの名称
- URLやファイルパス
## コードスタイル / Code Style
```javascript
// 良い例:コメントは日本語
function calculateTotal(items) {
// 合計金額を計算する
return items.reduce((sum, item) => sum + item.price, 0);
}
// 避けるべき例:コメントが英語
function calculateTotal(items) {
// Calculate total amount
return items.reduce((sum, item) => sum + item.price, 0);
}
これでkiroとのやりとりを日本語化できました。
他にも技術スタックやディレクトリ構成、コーディング規約を定義しておきましょう。
---
title: Task Manager Constraints
inclusion: fileMatch
fileMatchPattern: "task-manager-with-steering/*"
---
# タスク管理アプリ - 制約
## 出力先
このアプリのコードは `apps/task-manager/` 配下に出力する。
## 技術スタック
- フロントエンド: React + TypeScript + Vite + Tailwind CSS
- バックエンド: Node.js + Express + SQLite
## コード規約
- 関数コンポーネントのみ使用
- any型禁止
## 禁止事項
- 過度な抽象化
- 不要なライブラリの追加
- console.logの残存
今回は、上記に加えて、以下のコーディング規約の有無でどういった違いが出るかを比較してみました。
---
title: Task Manager Code Conventions
inclusion: fileMatch
fileMatchPattern: "task-manager-with-steering/*"
---
# タスク管理アプリ - コーディング規約
## シンプルさを優先
- **YAGNI (You Aren't Gonna Need It)**: 今必要ない機能は実装しない
- **DRY (Don't Repeat Yourself)**: 重複コードを避ける
- **KISS (Keep It Simple, Stupid)**: シンプルな実装を選ぶ
## 禁止事項
- 不必要なコメントを書かない(コードが自己説明的であるべき)
- 過度な抽象化を行わない
- 要件にない「便利機能」を追加しない
- 冗長な変数名を使わない
- 不要なprint/log文を追加しない
## コードスタイル
- 関数は1つの責務のみ持つ
- ネストは最大3階層まで
- 1ファイルの行数は200行以内を目安
- 必要最小限のimport文のみ記述
## 実装の優先順位
1. 動作する最小限のコード
2. 読みやすさ
3. 拡張性(明示的に要求された場合のみ)
design.md
specを元に設計書を生成してくれます。
問題があればspecを更新し、Refineボタンを押すことで再度design.mdを再生成してくれます。
tasks.md
設計に問題がなければ実装に進みます。
必須タスクとオプションタスクに分けて出力してくれるので、まずは必須タスクのみ実装してもらいましょう。
今回、タスクは以下のようになりました。
ほぼ同じ指定で2回コーディングさせてみましたが、タスクの分割の仕方は違うものの、大枠の内容は同じでした。
簡単なTODOアプリでもStep数はそこそこ多くなります。
## タスク一覧
1. プロジェクト構造とコア設定のセットアップ
2. データベース層の実装
- 2.1 SQLiteデータベーススキーマを作成
- 2.2 データベース接続モジュールを実装
- 2.3 データベース層のユニットテストを作成 *
3. バックエンドAPIの実装
- 3.1 Expressアプリケーションのセットアップ
- 3.2 タスクサービス層を実装
- 3.3 GET /api/tasks エンドポイントを実装
- 3.4 POST /api/tasks エンドポイントを実装
- 3.5 PATCH /api/tasks/:id エンドポイントを実装
- 3.6 DELETE /api/tasks/:id エンドポイントを実装
- 3.7 APIエンドポイントのユニットテストを作成 *
4. チェックポイント - バックエンドの動作確認
5. バックエンドのプロパティベーステストを実装 *
- 5.1 Property 1のテストを作成: タスク追加の永続性 *
- 5.2 Property 2のテストを作成: タスクタイトルのバリデーション *
- 5.3 Property 3のテストを作成: ステータス切り替えの冪等性 *
- 5.4 Property 4のテストを作成: ステータス切り替えのラウンドトリップ *
- 5.5 Property 6のテストを作成: タスク削除の完全性 *
- 5.6 Property 7のテストを作成: 作成日時の単調性 *
6. フロントエンドの基本構造を実装
- 6.1 Reactアプリケーションのセットアップ
- 6.2 型定義を作成
- 6.3 APIクライアントモジュールを実装
7. タスク一覧表示機能の実装
- 7.1 TaskListコンポーネントを実装
- 7.2 TaskItemコンポーネントを実装
- 7.3 TaskFilterコンポーネントを実装
- 7.4 タスク一覧表示のユニットテストを作成 *
8. タスク追加機能の実装
- 8.1 TaskInputコンポーネントを実装
- 8.2 タスク追加のユニットテストを作成 *
9. タスクステータス切り替え機能の実装
- 9.1 TaskItemにステータス切り替えボタンを追加
- 9.2 ステータス切り替えのユニットテストを作成 *
10. タスク削除機能の実装
- 10.1 TaskItemに削除ボタンと確認ダイアログを追加
- 10.2 タスク削除のユニットテストを作成 *
11. チェックポイント - フロントエンドの動作確認
12. フロントエンドのプロパティベーステストを実装 *
- 12.1 Property 2のテストを作成: タイトルバリデーション(クライアント側) *
- 12.2 Property 5のテストを作成: フィルタリングの正確性 *
13. 統合とエラーハンドリングの完成
- 13.1 すべてのコンポーネントを統合
- 13.2 エラーハンドリングを強化
- 13.3 統合テストを作成 *
14. レスポンシブデザインの最終調整
- 14.1 各ブレークポイントでのレイアウト調整
- 14.2 タッチデバイス対応の確認
15. 最終チェックポイント
---
*が付いているタスクはオプション(MVPではスキップ可能)
完成したアプリケーションを見ると様々な違いがありました。
1回目(A)

デザイン面は詳細を指示していないので、実装のブレが起きるは仕方ありませんが、採用技術にも違いがありました。
- 共通の技術
- Express(Webフレームワーク)
- SQLite3(データベース)
- CORS(クロスオリジン対応)
- TypeScript(型付け)
- Supertest(APIテスト)
- fast-check(プロパティベーステスト)
- 異なる技術
-
- モジュール形式
- A: require/module.exports 形式
- B: import/export 形式
-
- 開発サーバー
- A: ts-node-dev - Node.js + TypeScript
- B: tsx
-
- テストフレームワーク
- A: Jest + ts-jest
- B: Vitest
-
今回はお試しなので、どのようなライブラリを使っても問題ありませんが、実際の開発現場では抜け漏れなく利用技術を指定する必要がありそうです。
困った点〜複数アプリケーションのモノレポ管理〜
今回、同じspecから2回実装させて比較するために、2つの異なるアプリケーションフォルダを用意しました。
1つのリポジトリやディレクトリ配下に、kiroを使った複数アプリケーションを実装したい場合、specファイルやsteeringファイルはどのように配置するべきでしょうか。
同一リポジトリ内に、別のsteeringファイルがあると、足りない仕様についてはそちらを参照してしまう恐れがありそうです。
今回は以下のようなフォルダ構成にしました。
.kiro/
├── specs/
│ ├── task-manager-with-steering/
│ │ ├── design.md
│ │ ├── requirements.md
│ │ └── tasks.md
│ └── task-manager-without-steering/
│ ├── design.md
│ ├── requirements.md
│ └── tasks.md
├── steering/
│ ├── common/
│ │ └── language.md
│ ├── task-manager-with-steering/
│ │ ├── code-conventions.md
│ │ ├── structure.md
│ │ └── tech.md
│ └── task-manager-without-steering/
│ ├── structure.md
│ └── tech.md
task-manager-with-steering/
├── backend/
└── frontend/
task-manager-without-steering/
├── backend/
└── frontend/
以下の2つのアプリケーションを管理するリポジトリのイメージです。
- task-manager-with-steering
- task-manager-without-steering
specsの下にそれぞれ対応するディレクトリが存在します。(今回はrequirements.mdどちらも同じ)
steeringのうち、共通で適用したいものはcommonに配置して以下のように記載します
---
title: Language Rules
inclusion: always
---
アプリケーションごとに個別に適用したいものはfileMatchPatternを指定することで特定の階層やファイルに対してのみ適用できます。
---
title: Task Manager Code Conventions
inclusion: fileMatch
fileMatchPattern: "task-manager-with-steering/*"
---
これによりtask-manager-with-steering/というアプリケーションにのみ、コーディング規約を適用することができました。
また、アプリケーションコードの出力場所も明記しておくと良さそうです。
---
title: Task Manager Structure
inclusion: fileMatch
fileMatchPattern: "task-manager-with-steering/*"
---
# タスク管理アプリ - コード出力先
このアプリのコードは `task-manager-with-steering/` 配下に出力する。
検証の中で学んだベストプラクティス
ドキュメントを読み漁る中で便利そうなTipsや推奨事項を記載します。
ベストプラクティス1:機能単位でSpecを分割する。
TODOアプリ程度であればよいですが、アプリケーションの規模が大きくなってきたら機能単位で分割しましょう
.kiro/specs/
├── user-authentication/ # ログイン、サインアップ、パスワードリセット
├── product-catalog/ # 商品リスト、検索、フィルタリング
├── payment-processing/ # 決済連携、注文確認
└── admin-dashboard/ # 商品管理、ユーザー分析
メリット:
- 可読性の維持
- チーム開発でのコンフリクト防止
- 特定機能の更新が他に波及しない
出典: AWS Japan Blog - 負債にならないSpecファイルの扱い方
ベストプラクティス2:技術境界でSpecを分割する
タスクが増えすぎることを防止する効果があるようです。
Spec 1: アプリケーション層
Spec 2: インフラ層
メリット:
- タスクが適切な粒度に収まる
- マージ時のコンフリクトが起きにくい
- 明確な終了条件を持つタスク分割が可能
ベストプラクティス3:MVPから始める
タスク生成後、Kiroは「MVPから始めるか、フル実装するか」を質問してくるのでMVPで最小構成から実装を始めましょう。
出典: anti-pattern.co.jp - KIROの使い方徹底解説
ベストプラクティス4:Refineボタンで冗長なドキュメントを最適化
ドキュメントをそのままSteeringに入れると冗長になります。Refineボタンを使うと劇的に圧縮されます。
3,500行 → 102行に削減できたという記事がありました。
# 最適化前(人間向けドキュメント)
The addition operation takes two addends and returns their sum.
For example: {"operation": "add", "addends": [1, 2]} returns 3.
Nested expressions are supported...
(繰り返しの説明が続く)
# 最適化後(Kiro向け)
add: {operation: "add", addends: [a, b]} → sum
出典:Teaching Kiro new tricks with agent steering and MCP
Appendix
良い仕様書・設計書とは、誰に何度書かせても同じような実装になるものだと感じました。
今回の検証でsteeringの有無以上に、仕様の不明瞭な部分の多さによって出力にブレが出ることも分かりました。これは実装後の改修においても実装のブレが起こることに繋がるのではないでしょうか。
最後に、不明瞭な仕様や規約があれば質問してもらい、specやsteeringをブラッシュアップしてもらいましょう。
以下のようなプロンプトでspecとsteeringを点検できそうです。
1.技術選定についての確認
この機能の実装に必要な技術選定で、まだ決まっていない項目を洗い出して質問してください。
特に以下の観点で確認してください:
- テストフレームワーク
- 状態管理ライブラリ
- UIコンポーネントライブラリ
- ビルドツール
- リンター/フォーマッター
- その他の依存ライブラリ
HTTPクライアント
フロントエンドはfetch APIを使用していますが、axiosなどのライブラリは不要でしょうか?
バリデーションライブラリ
現在は手動でバリデーションしていますが、zodやyupなどのスキーマバリデーションライブラリは不要でしょうか?
〜以下略〜
2.コーディング規約についての確認
同様にコーディング規約についても不明瞭な点を明記して実装にブレが起きないようにしてください。
現在のcode-conventions.mdと実際の実装を比較した結果、以下の点が不明瞭または矛盾しています:
1. コメントの扱い
規約: 「不必要なコメントを書かない(コードが自己説明的であるべき)」
実装: // タイトルのバリデーション、// 入力変更ハンドラーなどのコメントが多数存在
質問:
- 関数の上の説明コメントは許可されますか?
- どのレベルのコメントが「不必要」と見なされますか?
- JSDocスタイルのコメントは必要ですか?
2. 命名規則
実装パターン:
- コンポーネント: PascalCase(TaskInput)
- 関数: camelCase(validateTitle)
- 定数: camelCase(validationError)
- ファイル名: PascalCase(TaskInput.tsx)
質問:
- 定数はUPPER_SNAKE_CASEにすべきですか?
- プライベート関数の命名規則は?
- イベントハンドラーはhandleプレフィックス必須ですか?
〜以下略〜
仕様や規約についても壁打ちしてもらうことで抜け漏れのない良い指示を与えられそうです。
まとめ
雑多な記事になってしまいましたが、仕様駆動開発の基本的な進め方と、SpecsやSteeringの重要さが分かりました。
プロンプトエンジニアリングと同じですが、AIの挙動を理解して制御するハックスキルが必要だと感じました。これからも良い指示が出せるように改良していきたいです。
何か1つでもこの記事から得るものがあれば幸いです。

