概要
タスク分解とは、実装の前に機能を小さな作業単位へ分割する実践です。各タスクは、単体でマージでき、単体でrevertでき、無関係な変更を巻き込まないことを目指します。コードを書く前の準備がプルリクエストの粒度を決めます。分解したタスクを起点にプルリクエストを作ることで、適切な粒度を維持したままプルリクエストを作り続けられます。メリット
着手前にタスクを洗い出して分割するのは遠回りに見えますが、開発サイクル全体で見れば確実な近道になります。見積もりの精度が上がる
大きな機能を丸ごと見積もるより、小さく具体的なタスクの積み上げの方が誤差が小さくなります。
対応方針を早く合意できる
タスクリストをIssueに書き、実装前にレビューしてもらうことで、考慮漏れや誤った前提を修正が安いうちに発見でき、手戻りが減ります。
プルリクエストの粒度が保たれる
分解したタスクを起点にプルリクエストを作れば、1つのプルリクエストが1つのことに注力した状態を保てます。
進捗が見え、引き継ぎが容易
タスクのチェックリストは状況を一目で読み取れるようにし、人から人へ、あるいは人からAIエージェントへの引き継ぎを容易にします。
良いタスクの条件
適切なサイズのタスクは、次の4条件を同時に満たします。壊さずにマージできる
その変更を単体で安全に統合でき、マージしてもアプリケーションは正常に動作します。
テストを含んでいる
実装と、それを裏づけるテストは同じタスクで出荷し、別タスクには分けません。
単独でrevertできる
巻き戻しても他のタスクに影響しません。
一度に読み切れる
レビュアーが中断せずに読み通し、全体を理解できる分量に収まっています。
まとめるか分けるか
境界を決めるのは凝集度です。二つの作業が同じタスクに属すかは、次の3つのチェックを順に当てて判断します。いずれかの答えがまとめるよう促すなら、まとめます。1
独立性を確認する
タスクAなしでタスクBは正しく動くか。動かないなら同じタスクにします。
2
完結性を確認する
タスクAは単体で意味のある、マージ可能な単位か。そうでないなら、意味を持たせるタスクへまとめます。
3
revert影響を確認する
タスクAをrevertするとタスクBも壊れるか。壊れるなら同じタスクにします。
常にまとめる
- 実装とそのテスト
- APIエンドポイントとルーティング
- データモデルとマイグレーション
常に分ける
- リファクタリングと新機能
- ライブラリ更新と機能開発
- パフォーマンス改善と機能開発
- データマイグレーションと機能開発
- Feature Flagの各段階(追加 → 有効化 → 削除)
- 互いに依存しない複数の機能
分解の手順
分解は反復的です。最初のリストが完璧である必要はなく、多くの人が見るほど、分解が進むにつれて精度は上がります。 ここでは「ユーザーデータの一覧を返すREST APIを追加する」タスクを例に、タスクリストを作成する実例を紹介します。1
要件からタスクリストのたたき台を作る
ざっくりした要件を、Issueのタスクリストとして書き出すところから始めます。この時点では大枠の1行で構いません。
2
単体で出荷できるスライスに展開する
大枠の1行を、単体で出荷できる単位に分解します。一覧取得・絞り込み・ページネーション・ソートが、それぞれ独立したタスクになりました。すべてを一度に実装するのではなく、小さな追加を積み重ねて機能を組み上げます。
3
職種をまたいでリストをレビューする
コードを書く前に、フロントエンド・バックエンド・プロダクトのレビュアーにリストを見てもらいます。議論を通じて曖昧な項目が具体化されます。この例では、レビューでの認識合わせを経て、nameの絞り込みが「nameの部分一致」に確定しました。
4
実装中も分割し続ける
実装が現実を明らかにしたら、リストに反映してさらに分割します。この例では、テストを書く中で退会ユーザーの扱いという隠れた要件が見つかり、一覧取得のタスクが「全件返す」と「退会ユーザーは一覧から除外する」の2つに分かれました。1つのタスクを肥大化させず、リストの更新と分割を実装中も続けます。
依存関係と並列化
リストが固まったら、タスク間の依存関係を整理し、並列に進められるタスクを特定します。互いに依存しないタスクは、別々の人が、あるいは複数のAIエージェントが同時に実装できます。 たとえばユーザーの一括登録機能は5つのタスクに分かれます。ドメインモデルが最初にあり、パーサーとバリデーターはそれだけに依存するため並列に進められ、サービス層が両者を組み合わせ、APIエンドポイントが最上位に載ります。タスクのIssue化
分解と依存関係の整理が終わったら、タスクごとにIssueを作ります。タスクリストのチェックボックスのままでは、担当者・議論・進捗をタスク単位で追跡できません。着手するタスクを独立したIssueに昇格させることで、1つのIssueが1つの作業単位になり、そのタスクに関する要件と議論が1箇所に集まります。 機能全体とタスクは、親子のIssueとして構成します。- 親Issue — 機能全体を表します。背景・目的と、分解したタスクリストの全体像を残し、各子Issueへのリンクで進捗を追えるようにします。
- 子Issue — 分解した各タスクを表します。そのタスクの要件と完了条件を書き、依存関係と並列化で整理した依存を明記します。親子関係を紐づける機能がツールにあれば、子の進捗を親から集約して追跡できます。
親Issue: ユーザーの一括登録機能を追加する
Sub-issues(0 / 5)
- Task 1: ドメインモデルを定義する
- Task 2: パーサーを実装する
- Task 3: バリデーターを実装する
- Task 4: サービス層を実装する
- Task 5: APIエンドポイントを追加する