AI駆動開発フローの完全設計図:0→1も1→2も迷わない9フェーズ実践ガイド
目次リンク
はじめに
AI駆動開発で多くのチームが直面する問題:
- どのフェーズで何をすべきか分からず手戻りが発生
- AIに丸投げして設計が曖昧なままコード生成
- 新規開発と改修で同じフローを使い、副作用が発生
- レビューで「なぜこう作ったの?」が答えられない
- 品質が安定せず、バグが頻発
この記事では、フェーズごとに何をなぜやるべきかを明確にしたワークフローと、品質を担保するための実践的なルールを紹介します。
全体フロー
0→1(新規開発)
推奨AI:
アイデア、調査、タスク分解:Opus、Sonnet、kimi
レビュー:Codex、Opus、Gemini Pro
設計:Opus、DeepSeek、kimi(軽いものなら)
実装:Opus、kimi、Codex、GLM
1→2(機能追加・改修)
0→1との主な違い:
- 調査: 変更地点と前回設計を必ず参照
- 副作用分析: 変更による影響範囲を徹底調査
- タスク分解: 軽微な変更ならスキップ可能
基本原則
1チケット = 1目的
なぜ必要か
- 仕様変更とリファクタを混ぜると、レビューで「どれが本質的な変更か」が分からなくなる
- 問題が起きた時に切り戻しができない
- レビュアーの負担が増大
何をするか
- 機能追加は機能追加のみ
- リファクタはリファクタのみ
- バグ修正はバグ修正のみ
Small PR原則
なぜ必要か
- 研究結果: 200行未満のPRを持つチームは、200行以上のPRを持つチームより40%多くのコードをデプロイできる
- 大きなPRはレビューの質が落ちる(見落としが増える)
- 問題が起きた時に原因特定が困難
- マージまでの時間が長くなる → コンフリクトリスク増大
何をするか
- 1PR = 1意図
- 差分は小さく(理想は200行未満、最大でも400行程度)
- レビューしやすく、マージしやすく、問題があれば戻しやすく
PR説明テンプレ(推奨)
- 目的(Why): なぜこの変更が必要か
- 変更点(What): 何を変更したか
- テスト内容: どうテストしたか
- 影響範囲: どこに影響があるか
- レビューガイド: レビュアーがどの順序でファイルを見るべきか
- ロールバック: 問題が起きた時の戻し方
コミットは意味単位
なぜ必要か
- 変更理由が追えないと、後から「なぜこの変更をしたか」が分からなくなる
- AIも履歴で理解しやすくなる
- 部分的な切り戻しが可能
何をするか
- 変更理由が追える粒度で積む
- コミットメッセージは明確に(50文字以内の要約 + 詳細説明)
- 1コミット = 1つの論理的変更
段階的リリース
なぜ必要か
- マージ = 即本番投入 は事故のもと
- 新機能が問題を起こしても、既存ユーザーへの影響を最小化したい
何をするか
- Feature Flagや設定切り替えで「マージ=即事故」を避ける
- カナリアリリース、Blue-Greenデプロイ等を活用
- 段階的にユーザーを増やす
各フェーズ詳細
Phase 1: アイデア
なぜ必要か
目的を明確にしないと全フェーズで手戻りが発生する
- 曖昧な要求 → 設計がブレる → 実装がズレる → レビューで大修正
- AIが勝手に機能追加 → スコープ肥大化 → 納期遅延
視覚化しないと認識齟齬が起こる
- 言葉だけの説明 → 人によって解釈が異なる
- 図で表現 → 全員が同じ理解を持てる
何をするか
-
図で可視化する(Mermaid推奨)
- フロー図、構成図、ER図など
- コードは書かない(設計の段階ではない)
- 複雑なロジックを視覚的に理解
-
問答法でユーザーの意図を引き出す
- 想像で書かない
- 「〇〇ですか?」と質問を繰り返す
- 最低3回は確認する
- 詳細に端的に現状を説明
-
専門用語を減らす
- とっつきやすく、理解しやすく
- チーム全員が理解できる言葉で
- 脳へのインプットを減らす
-
機能追加は必ず許可を得る
- ユーザーの許可なしに機能追加は禁止
- ハルシネーション防止
- スコープコントロール
- 自分が作りたいものではなく、ユーザーが作りたいものを引き出す
-
箇条書きで理解しやすく
- 長文よりも箇条書き
- 構造化された情報
失敗例と対策
失敗例:
- 開発者: 「ユーザー管理機能を作って」
- AI: 「了解しました。ログイン、登録、パスワードリセット、権限管理、プロフィール編集、2FA、OAuth連携を実装します」
- 結果: スコープ肥大化、納期遅延
対策:
- 開発者: 「ユーザー管理機能について確認させてください。まず、どんなユーザー情報を管理する必要がありますか?」
- AI: 「以下について教えてください:1. ユーザー情報の種類、2. 認証方式、3. 権限管理の必要性」
- 結果: 必要最小限の機能に絞れる
チェックポイント
- 図で可視化されているか?
- コードが含まれていないか?
- ユーザーの意図を質問で確認したか(最低3回)?
- 勝手な機能追加がないか?
- 専門用語が適切に説明されているか?
Phase 2: 調査
なぜ必要か
外部依存は最もハルシネーションが起こりやすい
- API仕様、ライブラリの制約を想像で書く → 実装時に動かない
- 古い情報を参照 → 非推奨機能を使ってしまう
- マイナーなAPIは制約が多いため、徹底的に文章化が必要
制約を知らないと後で作り直しになる
- レート制限を知らずに設計 → 本番で503エラー頻発
- 認証方式を理解せずに実装 → セキュリティホール
- バージョン互換性を確認せず → 本番環境で動かない
1→2では副作用分析が最重要
- 変更が他に影響する箇所を見落とす → バグ発生
- 前回の設計意図を理解せず変更 → 別の機能が壊れる
- データマイグレーションを見落とす → データ不整合
何をするか(0→1の場合)
-
外部依存を先に調査
- 使用予定のAPI、ライブラリ、フレームワーク
- 公式ドキュメントを徹底的に読む
- ハルシネーションが一番起こる場所を潰す
-
APIドキュメントを文章化
- マイナーなAPIは特に詳細に
- 制約、レート制限、認証方法、エラーケース
- バージョン情報、互換性
- サンプルコードの動作確認
-
技術的制約を洗い出す
- バージョン互換性
- パフォーマンス制約
- セキュリティ要件
- ライセンス制約
何をするか(1→2の場合・追加項目)
-
変更地点を特定
- どのファイル、どの関数が影響を受けるか
- データフローを追跡
- 依存関係を洗い出す
-
前回設計を参照
- なぜその設計にしたのか
- どんな制約があったのか
- ADR(Architecture Decision Records)を確認
- 前回の詳細設計をコンテキストに含める
-
副作用を徹底分析
- 変更による影響範囲
- 破壊的変更の有無
- データマイグレーション必要性
- 既存テストが壊れないか
- パフォーマンスへの影響
チェックポイント
- 公式ドキュメントを確認したか?
- 技術的制約を文書化したか?
- マイナーなAPIは特に詳細に調査したか?
- (1→2)変更地点を特定したか?
- (1→2)前回設計のADRを確認したか?
- (1→2)副作用分析を行ったか?
Phase 3: 設計
なぜ必要か
ここでコードを書くと詳細に引きずられる
- 実装の細かい部分に気を取られる
- 全体像が見えなくなる
- 本質的な設計判断ができなくなる
設計を複数ファイルに分けると管理が煩雑
- どこに何が書いてあるか分からなくなる
- 矛盾が発生しやすい
- レビュー時に全体像を把握できない
作成順序を間違えると手戻りが多い
- GUI先行 → 後からDB構造変更 → 全部作り直し
- 浅い層から作る → 深い層の制約を後から知る → 大幅修正
- 深い層から作る → 手戻り最小化
何をするか
-
コードは書かない
- 設計書、構成図、フロー図のみ
- 実装の詳細はここでは決めない
- 設計はコードを書くための場所ではない
-
1ファイルにすべて書く
- 全体像を1箇所で把握
- 矛盾を防ぐ
- 1ファイルで簡潔に
-
作業工程はタスク分解フェーズに任せる
- ここでは「何を作るか」に集中
- 「どう作るか」はタスク分解で
- 行数の無駄とレビューによる修正で1箇所の負担を減らす
-
設計は軽く詰める
- 難しいアルゴリズムはここで詰めない
- ロジックの穴を増やさないため
- 複雑にしないため
-
作成順序: DB → バックエンド → API → GUI/CLI
- 深い層から作る
- 「後から〇〇が必要だった」を防ぐ
- 手戻りを最小化
失敗例と対策
失敗例:
- GUI画面から設計開始
- 後からDB設計を変更
- APIの戻り値も変更
- フロントエンドも全修正
- 結果: 全部作り直し
対策:
- DBスキーマから設計
- データモデルを確定
- バックエンドロジックを設計
- API仕様を決定
- 最後にGUI設計
- 結果: 手戻り最小
チェックポイント
- コードが含まれていないか?
- 1ファイルにまとまっているか?
- DB → バックエンド → API → GUI/CLI の順序か?
- アルゴリズムを詳細に書きすぎていないか?
- 全体像が明確か?
Phase 4: 設計レビュー
なぜ必要か
設計の誤りは実装後に見つけると致命的
- 実装コスト × 10倍
- テストコスト × 20倍
- 手戻りによるモチベーション低下
- スケジュール遅延
「なぜ」を追求しないと最適解にならない
- 安易な解決策を採用 → 技術的負債に
- 代替案を検討しない → より良い方法を見逃す
- 短期的な解決に終始 → 長期的な問題が残る
検索を活用しないと車輪の再発明
- すでに解決済みの問題を1から作る
- 既存ライブラリで解決できることを自作
- 古い機能やハルシネーションを見逃す
何をするか
-
「なぜ」から始める
- なぜこの設計にしたのか
- なぜこの技術を選んだのか
- なぜこの構成にしたのか
- それでないといけない理由を明確に
-
他の方法がないか1つずつ確実に見る
- 全体を見て1つに的を絞る
- 完成度を上げ、レビュー回数を減らす
- 代替案を必ず検討
-
検索を活用して最新・最適を探す
- 古い機能を使っていないか
- もっと良いライブラリはないか
- ベストプラクティスに沿っているか
- コードの簡略化目的
-
詰めすぎない
- 機能は簡素に、分かりやすく
- 無駄のないコードを目指す
- 穴を防ぐ、ロジックの残りカスを消す
- 詰めすぎて詳細設計の意味を失わせない
チェックポイント
- 「なぜ」が明記されているか?
- 代替案を検討したか?
- 最新のベストプラクティスを確認したか?
- 過度に複雑になっていないか?
- 検索で古い機能やより良い方法を調査したか?
Phase 5: タスク分解
なぜ必要か
大きなタスクは並列作業できない
- 1人が全部やる → 時間がかかる
- 複数人で分担できない → リソース無駄
- 進捗が見えない
クリティカルパスが見えないと遅延する
- どのタスクが完了を遅らせるか分からない
- 優先順位が不明確
- ボトルネックに気づかない
AIは工数感覚がない
- 人間が触れない前提で計画
- AI実行時間を考慮
- 人間がさわれない前提
タスクの粒度が適切でないと効率が悪い
- 大きすぎる → 進捗が見えない、手戻りが大きい
- 小さすぎる → 管理コスト増、オーバーヘッド増
- マルチタスクがやりにくい
何をするか
-
1タスクは分けられる最小単位で分ける
- これ以上分割できない粒度まで細分化
- ただし0→1の場合は例外(次項参照)
- コンプリートを避ける
-
0→1ではハルシネーション防止のため少しだけ大きくしておく
- 新規開発は不確実性が高い
- あまり細かくすると文脈が失われる
- タスク間の依存関係が複雑になりすぎる
- AIが全体像を把握しやすいサイズに
-
工程を均等に分割
- マルチタスクをやりやすく
- 1タスク = 理想的には1-2時間程度(人間の作業時間)
- AI作業時間は別途考慮
-
クリティカルパスを作成
- どのタスクが全体を遅らせるか特定
- 優先順位を明確化
- ボトルネックを早期発見
-
AIが作る前提で工数を考える
- 人間が手を入れる部分は最小限
- レビューとチェックに時間を割く
- AI実行時間 + レビュー時間で見積もる
-
設計は詰めない
- タスク分解に集中
- 実装の詳細は詳細設計フェーズで
- ここでは積めないため
1→2の場合の注意
軽微な変更ならスキップ可能
- 1ファイルの小修正
- 単純なバグ修正
- 設定値の変更のみ
- 数行レベルの変更
複雑な変更なら必須
- 複数ファイルにまたがる
- データベーススキーマ変更
- 新機能追加
- アーキテクチャ変更
チェックポイント
- タスクが適切な粒度で分割されているか?
- (0→1)ハルシネーション防止のため少し大きめか?
- (1→2)最小単位まで分割されているか?
- クリティカルパスが明確か?
- 工程が均等に分割されているか?
- AIが実行可能な粒度か?
- (1→2)スキップすべきか判断したか?
Phase 6: 詳細設計
なぜ必要か
ライブラリ選定を誤ると後で変更できない
- 依存関係が複雑に絡む
- 全体を書き直しになる
- 移行コストが膨大
AIへの指示が曖昧だとハルシネーション多発
- ルールがない → 好き勝手に実装
- 道標がない → token無駄遣い
- 一貫性がない → コードの品質がバラバラ
静的解析を決めないと品質が安定しない
- AIの判断に任せると抜けが出る
- ルールで縛って均一な品質に
- 自動化しないと人的ミスが発生
テスト範囲を決めないと無駄か不足が起こる
- 全部テスト → 時間の無駄、メンテナンスコスト増
- 一部だけテスト → バグ見逃し、品質低下
- テストをすると品質も上がる
何をするか
-
ライブラリを決める
- 製品を完成させるための道具
- バージョン、ライセンス、メンテナンス状況を確認
- コミュニティの活発さ
- セキュリティアップデートの頻度
-
最適化、ルール、エージェント.md、skill、MCPを調整
- AIの道標を作る
- ハルシネーション防止
- 必要最低限のtokenで動く設計
- 一貫性のある出力を保証
-
静的解析ツールを決める
- lint、formatter、type checker
- AIで判断すると抜けがある部分を徹底
- 自動化で品質を担保
- pre-commitフックで自動実行
-
テストカバレッジ範囲を決める(テストピラミッド戦略)
-
ユニットテスト(基盤、最多)
- 個別の関数・メソッドを高速にテスト
- カバレッジは高く保つ
- TDD(Test-Driven Development)の実践推奨
-
統合テスト(中間層)
- コンポーネント間の連携を検証
- 外部依存(DB、API等)との連携
-
E2Eテスト(最上層、最少)
- ユーザー視点での重要なフローのみ
- 実行コストが高いため数を絞る
- 原則: 現実に起こり得ることは網羅的に、起こり得ないことは書いても無駄
- 注意: 逆ピラミッド(アイスクリームコーン型)にならないよう注意
-
ユニットテスト(基盤、最多)
-
詳細設計は1つずつ作る
- 設計を分けても、詳細設計を作るのは作業する1つのみ
- 手戻り防止
- フォーカスを維持
-
前回の詳細設計をコンテキストに加える
- 設計のブレを減らす
- 一貫性を保つ
- 過去の判断を参照
-
「なぜ」を明記する
- それでないといけない理由
- 無駄な設計、コードは手戻り原因
- 設計の大原則
テストピラミッドの重要性
/\
/E2E\ ← 少数:重要なユーザーフローのみ
/------\
/統合Test\ ← 中程度:コンポーネント間の連携
/----------\
/ユニットTest\ ← 多数:個別機能の検証(基盤)
/--------------\
なぜこの形が重要か
- ユニットテスト: 高速、安定、メンテしやすい
- E2Eテスト: 遅い、不安定、メンテが困難
- 下の層でテストできることは下でテストする(効率優先)
失敗例(逆ピラミッド)
- E2Eテストが多すぎる
- 実行に時間がかかる
- 不安定で頻繁に失敗
- メンテナンスコスト大
- 結果: テストが信頼されなくなる
チェックポイント
- ライブラリが決まっているか?
- 静的解析ツールが設定されているか?
- テスト範囲が明確か(テストピラミッド)?
- 「なぜ」が明記されているか?
- 前回設計を参照しているか?
- AIへのルール・道標が整っているか?
Phase 7: 詳細設計レビュー
なぜ必要か
設計レビューで見つからなかった穴を潰す
- より深いロジックミス
- エッジケースの考慮漏れ
- パフォーマンスボトルネック
- セキュリティ脆弱性
ここで見つければ実装前に修正できる
- 実装後に見つけると修正コスト大
- テストで見つけるとさらにコスト大
- 本番で見つけると致命的
設計で出る手戻りを早期発見
- データフローの矛盾
- 依存関係の循環
- パフォーマンス問題
- スケーラビリティ問題
何をするか
-
設計レビューと同じ観点
- 「なぜ」の追求
- 代替案の検討
- 最新情報の確認
-
より深いロジックミスをチェック
- アルゴリズムの正しさ
- エッジケースの網羅性
- エラーハンドリングの妥当性
- 境界値のテスト
-
設計で出る手戻りを頑張って見つける
- データフローの矛盾
- 依存関係の循環
- パフォーマンス問題
- セキュリティホール
-
テスト戦略の妥当性を確認
- テストピラミッドに沿っているか
- カバレッジが適切か
- Flakyテストを生まない設計か
チェックポイント
- ロジックに穴がないか?
- エッジケースを考慮しているか?
- パフォーマンス問題はないか?
- エラーハンドリングは適切か?
- セキュリティリスクはないか?
- テスト戦略は適切か?
Phase 8: 実装
なぜ必要か
ルールで縛らないと品質がバラバラ
- AIは自由度が高いと暴走する
- 統一感のないコードが生成される
- 保守性が低下
いきなり実装すると無駄なコードが混入
- 検証せず動かす → 不要なifが大量
- クリーンでないコード → 保守性低下
- 要らないロジックで複雑化
メモリ・CPU・DB負荷を考えないと遅くなる
- 取るデータ、残すデータは最低限に
- 早い = レスポンスが早い
- 回数が多ければ塵も積もる
- パフォーマンス問題は後から直すのが困難
副作用のある処理が散らばると テストしづらい
- I/O処理を外側に、ビジネスロジックを内側に配置
- 純粋関数を増やすことでテスト可能性が向上
何をするか
-
ルールで縛る
- 決まったレールで動く
- 1つ1つを丁寧に作る
- 縛れば縛るほど良いコードを作る
- コーディング規約の徹底
-
まず関数をすべて作り、TODOをすべて記述
- すべてのタスクを完遂
- お残しをなくす
- 実装漏れを防ぐ
-
複雑なロジックはまず検証から
- 検証せず動かしたコードは無駄なifで構成される
- 正しい動作を確認してから実装
- テストケースを先に書く(TDD)
-
検証後もクリーンで最低限のコードを1度書く
- 要らないロジックを消す
- リファクタリング前提
- 可読性を優先
-
メモリ、CPU負荷、DB負荷は最低限に
- 取るデータ、残すデータは最低限に
- メモリ、CPU利用率は少なく早くする
- 早い = レスポンスが早くなる
- N+1問題の回避
- 不要なクエリの削減
-
副作用は境界に寄せる
- I/O(DB/HTTP/ファイル等)は外側
- ロジックは内側へ
- テストしづらい設計を避ける
-
コーディング規約を守る
- ネストは浅く(早期return、分割、ガード節)
- 1行で書けることは1行で(可読性優先)
- 関数・変数名は意図が伝わる名前に
- エラー/例外の方針を統一
テストの書き方(AAAパターン)
テストコードは 3つの区切りで書く:
- Arrange(準備):前提・入力・モックなどを用意
- Act(実行):対象コードを呼び出す
- Assert(検証):結果が期待どおりか確認
なぜ必要か
- テストの可読性が上がる
- テストの意図が明確になる
- メンテナンスしやすくなる
チェックポイント
- ルールに従っているか?
- すべての関数が実装されているか?
- 複雑なロジックは検証済みか?
- クリーンなコードか?
- パフォーマンスを考慮しているか?
- 副作用は境界に寄せているか?
- テストはAAAパターンで書かれているか?
Phase 9: コードレビュー
なぜ必要か
レビューしないと品質が安定しない
- AIは間違える
- ハルシネーションは必ず起こる
- 人間のチェックが不可欠
「なぜ」を追求しないと最適化できない
- 冗長なコード
- 非効率なアルゴリズム
- メンテナンス性の低下
- 技術的負債の蓄積
関数ごとにレビューしないと精度が落ちる
- 全体を一度に見る → 見落とし多発
- 的を絞る → 精度向上
- 的確な返答が多い
綺麗なコードには綺麗なロジックを保てる
- メンテ性はAIにも現れる
- 次の修正時にAIが理解しやすい
- 技術的負債を防ぐ
何をするか
-
「なぜ」を追求
- なぜこのロジックにしたのか
- なぜこの関数に分けたのか
- なぜこの順序なのか
- 設計意図との整合性
-
関数ごとにレビューし最適化を図る
- 的確な返答が多い
- ロジックごとに的を絞ると精度が良くなる
- 1関数ずつ丁寧に
-
以下の観点でチェック
- 冗長なコードではないか
- 早期returnか(ネストを浅くする)
- 数行の関数ならまとめる必要なし(過度な分割を避ける)
- 関数の位置は最適か(読みやすい順序)
- 関数ネスト、ネストは浅く(3段階まで推奨)
- 当たり前だがみんなそこまでやらない
- メンテ性はAIにも現れる、綺麗なコードには綺麗なロジックを保てる
-
設計、詳細設計もコンテキストに含める
- 目的と、少ないコンテキストで全体像をくっきりと
- 設計意図からズレていないか確認
- ADRとの整合性
-
ツッコミは入れるが修正は行わない
- 役割を分ける
- レビュアーは指摘のみ
- 実装者が修正
- フィードバックループを回す
-
品質ゲートを通す
- lint / typecheck / test を通す
- CIでFailしたらマージ不可(例外を作らない)
- フォーマットは自動化する
レビュープロセス
レビュー速度を優先
- PRが提出されたら2時間以内にレビュー開始(理想)
- 最大でも1営業日以内に初回フィードバック
- レビュー待ち時間がボトルネックになりがち
レビューの責任分担を明確化
- DRAFT状態:早期フィードバックを求める段階
- READY FOR REVIEW:正式レビュー依頼
- 専門性に応じたレビュアー割り当て
建設的なフィードバック
- 「これは間違っている」ではなく「この部分について質問があります」
- 可能な限り代替案やリソースを提示
- 優れたPRは積極的に認める(モチベーション向上)
チェックポイント
- 「なぜ」が説明できるか?
- 冗長なコードがないか?
- ネストが深くないか(3段階まで)?
- 設計意図からズレていないか?
- レビューと修正の役割を分けているか?
- lint / typecheck / test が通っているか?
- 2時間以内にレビュー開始できるか?
ドキュメント整備(AIが迷わない入口)
なぜドキュメントが重要か
AIはプロジェクトの文脈を知らない
- 毎回ゼロから説明する手間
- 説明漏れで誤った実装
- チーム内で知識が属人化
ドキュメントがないと新メンバーが困る
- オンボーディングに時間がかかる
- 質問対応で既存メンバーの時間が奪われる
- 暗黙知が増える
README配置戦略
全てのディレクトリに README.md を設置
各READMEに含めるべき内容:
- 目的:このディレクトリは何のためにあるか
- スコープ:何が含まれ、何が含まれないか
- 入口ファイル:どこから読み始めるか
- 実行方法:どうやって動かすか
- よくあるタスク:典型的な操作手順
- 罠・注意点:ハマりやすいポイント
"まず読ませる"セット
プロジェクトルートに以下を配置:
-
README.md- プロジェクトの概要
- クイックスタートガイド
- 主要な構成要素へのリンク
-
CONTRIBUTING.mdorAGENTS.md- 開発ワークフロー
- コーディング規約
- AI使用時のガイドライン
- よく使うコマンド一覧
-
ARCHITECTURE.md- システムアーキテクチャ図
- 主要コンポーネントの責務
- データフロー
- 技術スタックと選定理由
READMEのメンテナンス
READMEは太らせすぎない
- 詳細は
/docsやADRへ逃がしてリンク - READMEは最小で新鮮に保つ
- 更新されないドキュメントは信頼を失う
定期的な見直し
- 四半期ごとに古い情報を削除・更新
- 新しいメンバーに読んでもらってフィードバックを得る
ADR(Architecture Decision Records)
なぜADRが重要か
ソフトウェアアーキテクチャの第二法則:「Why」は「How」より重要
知識の保存
- 人は異動・退職する
- 決定の背景を失わないために
新メンバーのオンボーディング
- 「なぜこうなってるの?」への回答
- 暗黙知を形式知に
意思決定の透明性
- 選択肢、トレードオフ、結果を明確化
- チーム全体での合意形成
将来の判断材料
- 似た状況で過去の決定を参照できる
- 同じ失敗を繰り返さない
ADRを作成すべき時
- アーキテクチャに大きな影響を与える決定(技術スタック選定、データベース選択等)
- 非機能要件に関わる決定(セキュリティ、可用性、スケーラビリティ等)
- 複数の選択肢があり、トレードオフを検討した結果の決定
- 将来のメンバーが「なぜ?」と疑問に思いそうな決定
ADRを作成しなくて良い時
- リスク・コスト・スコープが限定的な決定
- すでに標準やポリシーで定められている決定
- 一時的な回避策、PoC、実験的なもの
- 単一開発者の範囲で完結する小さな変更
ADRの基本構造
- タイトル:短い名詞句
- 日付:決定した日
- ステータス:提案中 / 承認済み / 却下 / 非推奨 / 置き換え済み
- コンテキスト:背景・課題(中立的な事実)
- 決定:何を採用するか(能動態で明確に)
- 検討した代替案:各選択肢のメリット/デメリット
- 結果:この決定により何が起こるか(ポジティブ/ネガティブ)
- 信頼度(オプション):低/中/高
ADRの運用ルール
-
コードに近い場所に配置:
/docs/adr/または各リポジトリのルート - バージョン管理:必ずGitで管理
- 不変性:承認後のADRは基本的に変更しない(新しいADRで置き換え)
- 簡潔に:1-2ページ程度
- レビュープロセス:PRでレビュー、チームで議論
AI駆動開発でのADR活用
- AIに実装を依頼する際、関連ADRを必ずコンテキストに含める
- 「ADR-005に基づいて実装して」と明示
- AIが生成したコードがADRに準拠しているか確認
品質ゲート(自動化で守る)
CI/CDパイプライン
フォーマットは自動化する
- pre-commit / lefthook / husky 等
- コミット前に自動整形
- 手動の手間を削減
CIでFailしたらマージ不可
- 例外を作らない(運用が壊れる)
- ステータスチェック必須化
- 全テストパス + lint通過 + typecheck通過が必須
段階的テスト実行
- PR作成時:ユニットテスト + lint
- マージ前:統合テスト
- デプロイ前:E2Eテスト
Flakyテストの撲滅
なぜFlakyテストは最優先で潰すべきか
- テストが信頼されなくなる
- CI/CDのボトルネックになる
- 開発者の時間を奪う
Flakyテスト防止策
- 時刻・乱数・外部I/Oは固定 or 注入(Clock/Random/HTTPなど)
- 並列実行時の競合状態に注意
- 非決定的な動作を排除
- テストの独立性を保つ
CODEOWNERS
なぜ必要か
- レビューが安定する
- 適切な専門家が必ずレビュー
- 責任範囲が明確
設定例
# データベース関連
/db/ @database-team
# フロントエンド
/frontend/ @frontend-team
# セキュリティ重要箇所
/auth/ @security-team
最適化の判断基準
Donald Knuthの格言
「早すぎる最適化は諸悪の根源である」
最適化すべき時
実測データに基づく場合のみ
- プロファイリングツールで実際のボトルネックを特定済み
- ユーザーに影響が出ている
- パフォーマンス要件が明確で、現在それを満たしていない
アーキテクチャレベルの決定時
- システム全体のパフォーマンスはアーキテクチャ設計に圧倒的に影響される
- 後から変更するとコスト大
- 例:データストレージの選択、通信プロトコル、並列処理モデル等
最適化すべきでない時
推測・仮定に基づく場合
- 利用状況が不明確な段階での最適化は誤った方向への最適化になりがち
- 「将来スケールするかもしれない」という理由だけで最適化しない
機能検証前の場合
- 100人のユーザーが製品を気に入っているか確認する前に、100万人対応の最適化をするのは時期尚早
- まず正しい機能を作り、ユーザーフィードバックを得る
可読性・保守性を犠牲にする場合
- 最適化されたコードは複雑になりがち
- トレードオフを理解し、メリットがコストを上回る時のみ実行
最適化の判断フレームワーク
実装する前に以下を自問する:
- 問題は明確か?
- 投資対効果は?
- トレードオフは何か?
- データはあるか?(プロファイリング結果)
- 代替案は検討したか?
段階的な最適化アプローチ
- まず動くものを作る(Make it work)
- 次に正しくする(Make it right)
- 必要なら高速化する(Make it fast)
AI使用時の注意点
AIに最適化させる前に「なぜ」を明示
- 「この処理が遅いから最適化して」ではなく
- 「プロファイリング結果でこの関数が全体の60%の時間を占めている。O(n²)をO(n log n)に改善できないか検討して」
最適化と機能追加を分離
- 1PR=1目的の原則を守る
- 最適化PRでは性能改善のみに集中
- ベンチマーク結果をPR説明に含める
まとめ
重要ポイント
-
フェーズごとに目的と役割が明確
- アイデア: 可視化と意図の引き出し
- 調査: ハルシネーション防止
- 設計: 全体像の把握
- レビュー: 早期の誤り発見
- タスク分解: 並列作業可能に
- 詳細設計: AIへの道標
- 実装: ルールで品質担保
- コードレビュー: 最適化と保守性
-
0→1と1→2は別フロー
- 1→2は副作用分析が必須
- タスク分解はスキップ可能な場合あり
- 0→1はタスクを少し大きめに、1→2は最小単位で
-
「なぜ」を追求することで手戻り防止
- 設計段階で誤りを見つける
- 実装後の修正コストを削減
- ADRで決定の背景を記録
-
Small PR原則で品質と速度を両立
- 200行未満推奨
- 40%多くデプロイできる
- レビューの質が上がる
-
テストピラミッドで効率的なテスト
- ユニットテスト:多数
- 統合テスト:中程度
- E2Eテスト:少数
- 逆ピラミッドに注意
-
ドキュメントとADRで知識を保存
- AIへの道標
- チームの共通理解
- 新メンバーのオンボーディング
-
品質ゲートで自動化
- CI/CDで品質担保
- Flakyテストは最優先で潰す
- CODEOWNERSで責任明確化
-
最適化は慎重に
- 実測データに基づく
- アーキテクチャレベルでは重要
- 推測では最適化しない
次のアクション
- このフローを自分のプロジェクトに適用
- 各フェーズのチェックリストを活用
- チームで振り返りを行い、継続的に改善
- ADRを導入し、「なぜ」を記録
- Small PR原則を実践
- テストピラミッドを意識