Spec-first-dev
DDDでものに名前を付け、BDDで仕様を定義し、それを満たす最小の変更を行い、証拠をもって証明します。スタックに依存しません。
1. コードを書く前に考える
- 前提を明示する。リクエストが不明瞭だったり複数の解釈が可能な場合は、それらを列挙して質問する。黙って選択してはいけない。
- よりシンプルなアプローチが存在するなら、その旨を伝えて提案する。
- タスクが触れるコードを読む。変更が及ぶすべてのもの(呼び出し元、テスト、フィクスチャ、設定、エクスポート)と、壊す可能性のあるもの(破壊または公開されるデータ、動作しなくなる呼び出し元)をリストアップする。それがスコープであり、余分な機能は含めない。スキップした余分な機能は1行で記載する。
- 最初の書き込みの前に、作業に適した名前(例:
feat/<feature>、fix/<bug>)でmainからブランチを作成する。読み取り専用の作業にはブランチは不要。
2. ドメインのモデル化(DDD)
コードを書く前に、数行で以下を書き留める:
- 境界付けられたコンテキストとそのユビキタス言語:ドメインエキスパートが使用する用語。既存のコードベースの用語を再利用し、必要な場合にのみ新しい用語を追加する。
- 集約とその不変条件:常に真でなければならないこと。
- コード、テスト、メッセージ内の名前はこれらの用語を使用する。汎用的な名前(
handle、process、manager、utils)は拒否する。 - ドメインロジックはプレーンなデータに対する純粋関数とする。I/O(DB、ネットワーク、クロック、ランダム性)はエッジのポートの背後に配置し、注入する。
docs/specs/<feature>.mdに保存する。
これは、新しいドメイン概念を追加しない些細な変更ではスキップしてよい。
3. 振る舞いの仕様化(BDD)
Given/When/Thenシナリオをドメイン言語で記述する。振る舞いごとに1つ、エッジケースと失敗ケースを含める。それぞれは実装ではなく観察可能な振る舞いを記述する。明白でないシナリオについてはユーザーの承認を得る。それらが契約である。docs/features/<feature>.featureに保存する。
4. 計画
複数ステップの作業には、docs/plans/<feature>.mdに短い計画を書く:各ステップとその検証チェック。既存の仕様から続行する場合でも、最初に計画を書く。そして、ユーザーがレビューするのを待つ;承認されるまで決して実行してはならない。完全に機能する最初のオプションを選ぶ:
- 存在する必要があるか? 不要ならスキップ。
- このコードベースに既にあるか? 周囲のコードと同様に使用する。
- 標準ライブラリまたはプラットフォームの機能か? それを使用する。
- インストール済みの依存関係か? それを使用する。数行のために新しいものを追加してはいけない。
- 一目で読者が理解できる1行か? それを使用する。
- それ以外の場合、動作する最小のコード。
5. 実行
オーケストレーション
タスクを実行しようとするとき(仕様や計画の有無にかかわらず)、それらが以下の条件に適合するか確認する:いくつかの分離可能な項目(例:3つ以上の修正)、独立したステップ、または明らかに難易度の異なるステップ。適合する場合は、(このファイルの隣にある)orchestration.mdを読み、最初の編集の前に2つの選択肢(AskUserQuestionを介して)を尋ねる:計画を作成する場合は計画レビューと同じターンで、それ以外の場合はすぐに。常に尋ねること;他の承認(計画、仕様、「OK」)は選択としてカウントされない。タスクが適合しない場合は、インラインで実行する。
レッド、グリーン、リファクタリング、シナリオごとに
- シナリオを失敗するテストに変換する。実行する。正しい理由で失敗することを確認する。
- テストをパスする最小のコードを書く。実行する。
- この変更で乱雑になった部分のみリファクタリングする。
- バグ修正:最初に失敗するシナリオで再現し、関数のすべての呼び出し元をgrepし、共有コード内の根本原因を一度だけ修正する。
6. 差分を外科的に保つ
- 必要なものだけに触れる。既存のスタイルに合わせる;隣接するコードを改善しない。変更された各行はリクエストに遡れること。
- 変更によって生じた孤児だけを削除する;他のデッドコードに言及するが、削除してはいけない。
- 誰も求めていない抽象化、ラッパー、オプション、設定、「後で使う」コードはなし。追加よりも削除を優先する。
- 移動したコードは、そのエラーハンドリングとバリデーションを維持する。
- コメントは理由のみ、1行で。既知の制限には
shortcut: <制限>, <アップグレード時期>と記述する。 - 決して削減してはいけない:信頼境界でのバリデーション、データ損失を防ぐエラーハンドリング、セキュリティ、アクセシビリティ、ユーザーが要求したもの。
7. 完了を宣言する前に検証する
テストとビルドまたは型チェックを実行する。出力を読む。実際の結果を報告する;何かが失敗したか実行されなかった場合は、その旨を伝える。「動作するはず」は不可。
8. 返信
スキップまたは確認しなかったこと、およびユーザーが知っておくべきリスクを1〜2行で記述して終了する。