ENECHANGE Developer Blog

ENECHANGE開発者ブログ

クライアント案件単位で開発を管理する「プロジェクト駆動開発」ワークフロー

はじめに

弊社では複数のクライアントが利用するAPIを開発・運用しているのですが、たまにこんな課題に直面することがあります。

  • 「この機能、どのクライアントの要望で追加したんだっけ?」
  • 「なぜこの設計判断をしたのか、当時のSlackを探しても見つからない...」
  • 「新メンバーに経緯を説明したいけど、ドキュメントがない」

私たちのチームではこれらの課題を解決するために「プロジェクト駆動開発」とも呼べるワークフローを導入しました。 本記事ではその概要と実際に運用してみて感じたメリット・デメリットを紹介します。

スペック駆動開発の限界

テスト駆動開発(TDD)やスペック駆動開発はコードの品質を担保する優れた手法です。 しかし、これらの手法ではコードに表現されない情報を管理するのが難しいという側面があります。

  • なぜその仕様になったのか(ビジネス上の経緯)
  • どのクライアントの要望だったのか
  • 検討したが採用しなかった選択肢は何だったのか

コードやテストには「何を作ったか」は残りますが「なぜ作ったか」「誰のために作ったか」は残りにくいのです。


プロジェクト駆動開発ワークフローとは

私たちが導入したワークフローは開発案件(プロジェクト)を起点として、要望から実装までを一貫して管理するというものです。

3階層の開発粒度

開発案件を以下の3階層に分解して管理します。

開発・案件(Development)
  └─ 機能(Feature)
       └─ タスク(Task)
階層 定義 期間目安
Development クライアント案件または社内改善案件 数週間〜数ヶ月
Feature 独立してデプロイ可能な機能単位 数日〜数週間
Task 独立してPRを出せる作業単位 数時間〜数日

ドキュメントをリポジトリで管理

各階層で以下のようなドキュメントを作成しリポジトリ内で管理します。

  • issue.md - 案件/機能/タスクの説明(常に最新状態を維持)
  • status.yaml - ステータス管理
  • report.md - タスク完了レポート
  • dependencies.yaml - タスク間の依存関係

これらはSlackやNotionではなくコードと同じリポジトリに格納されます。

PRも3階層

ブランチとPRも案件構造に対応させます。

main
  │
  ├── dev/クライアント名-案件名 (Development PR)
  │       │
  │       ├── feature/機能名 (Feature PR)
  │       │       │
  │       │       ├── task-01 (Task PR)
  │       │       └── task-02 (Task PR)
  │       │
  │       └── feature/別の機能名 (Feature PR)

Claudeスラッシュコマンドによる自動化

ワークフローの各フェーズはClaude Codeのスラッシュコマンドで実行します。 案件立ち上げ、機能設計、タスク実装、レビュー対応など、定型的な作業をコマンド化することで一貫した品質でドキュメントとコードを生成できます。

ワークフロー全体図

flowchart TD
    Start([案件開始]) --> DevIssue["要望整理<br/>Development, Feature issue.md 作成"]
    DevIssue --> DevPR["Development PR 作成"]

    DevPR --> FeatureIssue["機能設計、タスク分割<br/>Feature issue.md 修正<br/>Task issue.md 作成"]
    FeatureIssue --> FeaturePR["Feature PR 作成"]

    FeaturePR --> TaskList{"開始可能タスク確認"}

    TaskList --> TaskStart["タスク実装、Task PR 作成"]

    TaskStart --> ImplComp["実装完了"]
    ImplComp --> Review["レビュー<br/>report.md 作成"]

    Review --> TaskPRMerge["Task PR マージ"]
    TaskPRMerge -->|No| CheckTasks{残タスクあり?}

    CheckTasks -->|Yes| TaskList
    CheckTasks -->|No| FeatureMerge["Feature PR マージ"]

    FeatureMerge --> NextFeature{次の機能あり?}
    NextFeature -->|Yes| FeatureIssue
    NextFeature -->|No| DevMerge["Development PR マージ"]

    DevMerge --> DevComplete([案件完了])

    %% AI が作業(青系)
    style DevIssue fill:#e1f5fe,stroke:#0288d1
    style DevPR fill:#e1f5fe,stroke:#0288d1
    style FeatureIssue fill:#e1f5fe,stroke:#0288d1
    style FeaturePR fill:#e1f5fe,stroke:#0288d1
    style TaskList fill:#e1f5fe,stroke:#0288d1
    style TaskStart fill:#e1f5fe,stroke:#0288d1
    style Review fill:#e1f5fe,stroke:#0288d1

    %% 人間によるレビュー(黄系)
    style ImplComp fill:#fff9c4,stroke:#f9a825
    style CheckTasks fill:#fff9c4,stroke:#f9a825
    style NextFeature fill:#fff9c4,stroke:#f9a825

    %% PR マージ(緑系)
    style TaskPRMerge fill:#c8e6c9,stroke:#388e3c
    style FeatureMerge fill:#c8e6c9,stroke:#388e3c
    style DevMerge fill:#c8e6c9,stroke:#388e3c

    %% 開始・完了
    style Start fill:#f5f5f5,stroke:#9e9e9e
    style DevComplete fill:#f5f5f5,stroke:#9e9e9e

*青いブロックはスラッシュコマンドによる実行


導入してよかったこと

1. 要望漏れが起きにくい

要望レベルからリポジトリのドキュメントとして管理するため、「あれ、この要件対応したっけ?」という事態が発生しにくくなりました。 issue.mdに要件を記載し、それを機能→タスクへと分解していく過程で漏れがあれば気づきやすい構造になっています。

2. 開発の経緯がドキュメントとして残る

「なんでこの実装にしたんだっけ?」という疑問が生じたときSlackを遡って探し回る必要がなくなりました。

  • 設計判断の理由はissue.mdに
  • 実装時に発見した課題と対応はreport.mdに
  • 採用しなかった選択肢も記録される

将来のメンテナンスや新メンバーのオンボーディングにおいて大きな価値を発揮すると期待しています。

3. クライアント案件と実装の紐付けが明確

ディレクトリ名やブランチ名にクライアント名を含めることで「この変更はどのクライアントの案件か」が一目でわかります。 複数クライアントの案件が並行して進む場合にも混乱を防げます。


微妙だったこと

1. ドキュメント量が多い

各階層でissue.md、report.md、status.yamlなどを作成するため出力されるドキュメントの量は決して少なくありません。 PRの差分にドキュメントが多く含まれることになり見た目のボリュームが増えます。

2. レビュー負荷が高め

コードだけでなくドキュメントにも目を通す必要があるためレビュアーの負荷は従来より高くなります。 ただし、ドキュメントを読むことで実装の意図が理解しやすくなる側面もあり一概にデメリットとは言い切れません。


まとめ

プロジェクト駆動開発ワークフローは、スペック駆動開発をラップする上位概念として機能します。 コードの品質保証はスペック駆動で行いつつ、ビジネス上の経緯や意思決定はプロジェクト単位のドキュメントで管理する、という二層構造です。

ドキュメント量の増加というトレードオフはありますが、複数クライアントの要望を扱うプロダクトにおいては「なぜその機能が存在するのか」を追跡可能にすることの価値は大きいと考えています。