機能設計提案スキル
目的
実装を導くための技術設計文書を作成します。実際のコードを書くことなく、アーキテクチャ、パターン、設計上の判断を提供します。
使用すべきタイミング
- 機能のコンセプトと要件が存在している場合
- 実装アプローチを計画する準備ができている場合
- アーキテクチャと設計パターンを文書化する必要がある場合
前提条件
- 機能コンセプトが
docs/features/NNNN-feature-name/concept.mdに存在すること - 要件が
docs/features/NNNN-feature-name/requirements.mdに存在すること - ユーザーが技術的アプローチを理解していること
手順
1. 前提条件の確認
# コンセプトと要件が存在するか確認
ls ./docs/features/NNNN-feature-name/concept.md
ls ./docs/features/NNNN-feature-name/requirements.md
いずれかが存在しない場合は、先にこれらの手順を完了してください。
2. アイデア熟成ドキュメントの確認
ls ./planning/NNNN-feature-name/idea-honing.md 2>/dev/null
存在する場合は、アイデア熟成プロセスで議論された設計上の洞察や技術的考慮事項を確認します。
3. 設計テンプレートのコピー
cp ./docs/features/0000-templates/design.md ./docs/features/NNNN-feature-name/
4. 概要の記入
アーキテクチャと設計アプローチの概要を記述します。コンセプトと要件を参照します。
5. 重要な制約の特定
主要な操作ごとに、以下を問いかけます。
- これを実装する「間違った」方法は何か?
- 必要とされるパフォーマンス特性は?
- 維持しなければならない不変条件は?
次の内容で「重要な制約」テーブルを記入します。
- ID: CC-1, CC-2 など
- 制約: 特定の方法で実装しなければならないこと
- 理由: なぜそうするのか(パフォーマンス、正確性、セキュリティ)
- アンチパターン: レビューで却下すべき間違ったアプローチ
これは実装ミスを防ぐための最も重要なセクションです。 具体性が重要です—曖昧な制約は役に立ちません。
6. アーキテクチャの定義
全体構造を説明します。
- コンポーネント間の関係
- データフロー
- レイヤーの責務
- 統合ポイント
必要に応じて、ASCIIアートを使ったシンプルな図を使用します。
7. 解決メカニズムの説明
このセクションは「なぜ」(コンセプト)と「何を」(アーキテクチャ)の橋渡しをします。 コンセプトで特定された各コア課題に対して、設計がどのように対処するかを説明します。
各課題に対して、次の項目に答えます。
- 根本的な問題は何か?(concept.md より)
- どのアーキテクチャ要素がそれに対処するか?
- なぜこのアプローチが機能するのか?
- 別の方法で行った場合、何が失敗するか?
テーブルまたは構造化リストとしてフォーマットします。
| 課題 | アーキテクチャ要素 | なぜ機能するか |
|---|---|---|
| コンセプトからの課題 | それに対処するコンポーネント/パターン | メカニズムの説明 |
執筆者を助けるプロンプト:
- 「『これはXをどう解決するのか?』と聞かれたら、特定のコンポーネントを指し示せるか?」
- 「新しいエンジニアが、なぜこの設計が代替案より選ばれたのかを理解できるか?」
- 「主要なコンポーネントそれぞれに、問題に結びついた明確な存在理由があるか?」
このセクションにより、レビュアーは設計が単に妥当なコード構造を説明するだけでなく、実際に提示された問題を解決することを確信できるようになります。
8. ドメインモデルの定義
コアとなる型と操作を指定します。
型
- 目的と役割
- 主要なプロパティ
- 検証ルール
- 他の型との関係
操作
- 関数シグネチャ(概念的なもの)
- 何を行うか
- 主要な動作
- 不変条件(常に真であるべきこと)
9. モジュール構造の定義
コードの整理方法を示します。
- ディレクトリ構成
- モジュールの責務
- ファイル構成
- 関心事の分離
モジュールサイズ制限: このプロジェクトではモジュールあたり550行の制限を適用しています(scripts/lint_loc.py を参照)。
モジュールを設計する際には、コンポーネントがこの制限を超える可能性があるかどうかを検討してください。
超える可能性がある場合は、事前に内部の分割を計画します。成果物の種類ではなく機能単位で分割してください(例: builder.rs, searcher.rs)。
リンターの出力には、制限を超えた場合のリファクタリングガイダンスが含まれます。
implブロックをまとめて保持する: ある型に対するすべての impl ブロックは1つのファイルに配置します。
implブロックを複数のファイルに分散させると、読者(およびAI)がその型の全体像を把握するのが難しくなります。
型の実装が大きすぎる場合は、implブロック自体を分割するのではなく、ヘルパー関数や内部コンポーネント型に委譲します。
// ✅ 良い例: 単一の impl ブロックがヘルパーに委譲
impl KnowledgeIndex {
pub fn build(&self, path: &Path) -> Result<()> {
self.builder.build(path) // 内部コンポーネントに委譲
}
}
// ❌ 悪い例: implブロックが複数のファイルに分割
// facade/mod.rs: impl KnowledgeIndex { fn new() ... }
// facade/build.rs: impl KnowledgeIndex { fn build() ... }
// facade/search.rs: impl KnowledgeIndex { fn search() ... }
10. 設計パターンの文書化
関連するパターンとそれがなぜ適用されるかを説明します。
- どのパターンを使用するか
- 問題にどのように適合するか
- 実装のガイダンス
11. 設計上の判断の文書化
代替案間の重要な選択については、「設計上の判断」セクションにエントリを追加します。
- 何が決定されたか
- どのような代替案が検討されたか
- なぜこのオプションが選ばれたか
- それが実装に何を意味するか
これにより、実装者が推論を理解するのに役立つ記録が作成されます。
12. 実装ガイダンスの追加
実装者向けの主要な考慮事項:
- 重要な制約をIDで参照する
- パフォーマンスに関する考慮事項
- テストアプローチ
- 対応すべきエッジケース
13. コードを最小限に保つ
覚えておくべきこと:
- 最小限の例示コードを使用する
- アーキテクチャと判断に集中する
- 実装者を導き、実装しない
- 必要に応じて要件をIDで参照する
検証
設計文書を検証します。
# ファイルが存在するか確認
ls ./docs/features/NNNN-feature-name/design.md
# 内容があるか確認
head -50 ./docs/features/NNNN-feature-name/design.md
よくある問題
コードが多すぎる: 大きなコードブロックがある場合は、削除してガイダンスに集中します。
抽象的すぎる: 設計が曖昧な場合は、具体的な型名とモジュール構造を追加します。
アーキテクチャの欠落: 詳細に入る前に、全体構造が明確であることを確認します。
要件を参照していない: 設計上の判断を特定の要件IDにリンクします。
解決メカニズムの欠落: 設計が構造を説明しているが、なぜ問題を解決するのかを説明していない場合は、「解決メカニズム」セクションを追加し、課題をアーキテクチャ要素にマッピングします。
次のステップ
設計作成後:
- 実装者と共に実現可能性をレビュー
- フィードバックに基づいて改善
- 設計が固まったら、
propose-feature-test-planスキルを使用してテスト計画を作成 - その後、
propose-implementation-planスキルを使用して実装計画を作成