


拡張できるGoサービスに機能を足し、設定が上書きされても通るテストを書く
下流のビルドで名前や設定が変えられるGoのサービスを直す時に使う。ログにトレースのつながりを残し、新しいツールを正しいグループに登録し、設定の上書きがあっても公開の動きをテストして、生成される文書も直す。
このAIルールを使うには
## 編集の前に、変更を受け持つパッケージを見つける
コードを変更する前に変更内容を分類し、正本の所在を特定する。
- コマンドのエントリポイント、ドメインパッケージ、設定層、通信・認可層、プロトコル実装、出力層、機能レジストリ、バージョンメタデータを特定する。
- ビジネスロジックは、コマンド配線や配布用ラッパーではなく、担当するソースパッケージに置く。
- 言語パッケージ用ディレクトリとインストーラー用ディレクトリは、バイナリ配布の薄いアダプターとして扱い、パッケージングまたはバージョン作業の場合だけ変更する。
- 影響範囲を規定するビルド定義、テスト設定、近接する実装、ユーザー向け文書を読む。
- 編集前に、作成対象のソースと生成ファイルおよびビルド成果物を区別する。
- 影響を受けるすべてのハンドラー、公開型、登録地点、設定経路、テスト、文書、パッケージ面を列挙する。
並行する別構造を導入せず、リポジトリで確立された配置と命名規則を使う。
## ログはコンテキスト付きのラッパーで書き、トレースとつなげる
本番コードがログを記録する時は、必ずリポジトリのコンテキスト対応ログラッパーを使う。
- ログ記録地点までリクエストコンテキストを引き回し、呼び出し経路がまだコンテキストを持たない場合は関数へコンテキスト引数を追加する。
- ラッパーがテレメトリ相関用に記録を拡充する場合、フレームワークの基本コンテキストロガーを直接呼び出さない。
- 関数が新しいトレーススパンを開始した場合は、スパン開始後にコンテキスト対応ロガーを再取得する。開始前に取得したロガーには古いスパンコンテキストが残る。
- ログ連携機構がログを正しいトレースへ関連付けられるよう、構造化された値を有効なコンテキストに紐付けておく。
- 本番コードでは返されたすべてのエラーを確認・処理し、捨てない。
- 診断情報を追加する時も、リポジトリで確立された秘匿化、認可、可観測性の境界を維持する。
ログ文の存在だけに頼らず、観測可能な結果を通じて相関とエラー挙動を検証する。
## 新しいツールを、ハンドラー・グループ・登録の順で足す
新しい機能は実装前に設計し、名前、グループ分け、入力スキーマ、挙動、評価範囲を確認する。
1. 機能のロジックを担当するハンドラーを実装する。
2. 公開ツールまたはコマンドの契約を定義し、ハンドラーへ接続する。
3. 適切な機能グループへ追加し、該当するものがなければ目的を絞ったグループを作る。
4. 新しいグループをリポジトリの初期化経路から登録する。
5. 挙動テスト、設定リファレンス、生成カタログ、ユーザー向け文書をまとめて更新する。
各機能グループは専用ディレクトリに置く。登録経路を重複させたり、内部実装の詳細を露出する名前を付けたりしない。
## 決められたビルドターゲットを使い、頼まれない限りデプロイしない
記憶からコマンドを組み立て直さず、リポジトリで宣言されたビルドターゲットを使う。
- 実行前に、どのビルドターゲットがソースを整形し、モジュールを整理し、単一プラットフォームをコンパイルし、または対応する全プラットフォームをビルドするか把握する。
- ビルドターゲットが依存関係メタデータや生成ファイルを意図的に書き換える場合があるため、実行後の差分を確認する。
- モジュールを導入した後は依存関係の宣言を整理された状態に保ち、リポジトリでバージョン固定された静的解析ターゲットを実行する。
- 明示フラグ、環境変数、既定ファイル、クラスター内設定の間で文書化された優先順位を含め、対応するローカル実行モードとリモート実行モードを維持する。
- 初回にツールや環境をダウンロードするテストまたはlintターゲットは、その前提を文書化する。ネットワークへ接続できない場合は、コード不良ではなくセットアップ失敗になることがある。
- サービスロジックを重複させず、パッケージ管理用ラッパーを薄く保ち、コンパイル済みバイナリと同期する。
ダウンロード、公開、push、deployを行うターゲットは外部操作の境界として扱う。先に契約を確認し、タスクがリリース作業を明示的に含まない限り、公開またはdeployを絶対に実行しない。
## 非公開の関数ではなく、公開の動きと境目のケースをテストする
公開APIをブラックボックスとして検証し、実用的な場合は実装本体または統合テストを優先する。
- リポジトリのスイート規則に従ってテストを構成し、各テストファイルに対応するスイートを用意する。
- ネストしたサブテストで関連シナリオをまとめ、各ケースに挙動を表す説明的な名前を付ける。
- 各ケースでは、1つの挙動を1つの焦点を絞ったアサーションで証明するのが望ましい。
- テストを非公開関数へ結合せず、成功経路、コールバック、状態変化、観測可能な結果を網羅する。
- nilまたはnull、空のコレクション、無効なインデックス、型の不一致、不正な入力、エラー経路の境界ケースを追加する。
- 成功しなければテストが成立しないセットアップ操作には前提アサーションを使い、その後に期待するエラーまたは値を明示的に検証する。
- テストを短くするためだけにエラーを無視してはならない。
不具合には、まず範囲を絞った失敗するテストを実行する。修正後に影響を受けるパッケージまたはスイートを実行し、最後にリポジトリで必要な全テストターゲットを実行する。
## 既定値や名前が上書きされても、設定のテストが通るようにする
下流ビルドが既定値、機能名、有効な機能セットを上書きしても、設定テストは有効でなければならない。
- 通常のテストスイートは、上書きのない基本設定から開始し、その上へテスト固有の設定を重ねる。
- 単純な設定では、デコードした値をスイートの既存設定へマージし、テスト基盤が設定済みのランタイム項目を維持する。
- 遅延値またはプリミティブ値を保持するセクションでは、そのセクションを完全に解析するために必要なメタデータ対応の2段階リーダーを使う。
- 設定全体を読み込んだ後は、接続経路、表示形式、読み取り専用状態など、ランタイム専用項目を明示的に復元する。
- 再読み込みテストでは、実行中サービスが使う上書き対応の既定値から候補設定を意図的に作り、有効なランタイム項目を継承する。
- 必要な機能は既存リストへ追加し、想定した上流の既定値でリスト全体を絶対に置き換えない。
- ブランド変更可能な公開名は動的に解決する一方、パーサー契約が要求する場合は、パーサーのリテラル登録キーを固定したままにする。
- 上書き対象になり得る既定値、公開名、機能セットをアサーションへ直書きしてはならない。
設定変更がこれらの境界をまたぐ場合は、基本挙動と少なくとも1つの上書き経路をテストする。
## 共通のテスト補助を1か所に置き、準備の失敗と不具合を分ける
汎用テストヘルパーはリポジトリ内の共有テスト領域に置き、目的、入力、例を明確に文書化する。
- 複数のパッケージで再利用できるよう、ヘルパーを1つの機能に依存させない。
- 本番挙動を迂回する低水準の近道より、現実的なユーザー操作またはプロトコル操作を優先する。
- ローカルクラスターシミュレーター、ダウンロード済み環境、認証情報、必要なネットワーク接続を含め、テストの前提条件を明示する。
- 診断ではセットアップ失敗と製品の失敗を分ける。
- 価値の低いケースで指標を水増しせず、特に境界条件と失敗経路について公開APIの高いカバレッジを目指す。
- テスト設定、エイリアス、生成fixtureを有効なテストランナーに合わせる。
下流でカスタマイズされる場合は、名前を変更した機能、変更された既定値、設定の再読み込みを代表するテストを含める。
## 文書は生成ツールで直し、配布パッケージを同じバージョンにそろえる
コードまたは設定変更の影響を受ける正本をすべて更新する。
- リポジトリ規則で定められている場合、新しい文書のファイル名には小文字を使う。
- 機能の影響に応じて、索引、設定リファレンス、プロンプト、ログ、可観測性、認証、連携ガイドを更新する。
- 生成された表とリファレンス節は生成内容として扱い、マーカーペアを維持し、承認済みジェネレーターで更新する。
- リポジトリ方針が明示的に求めない限り、生成された節を直接編集したり、ビルド成果物をコミットしたりしない。
- ネイティブバイナリ、コンテナイメージ、言語パッケージ用ラッパーを、同じバージョンのサービス挙動に合わせる。
- 変更に関係する、文書化済みのビルド、テスト、lint、文書生成、範囲を絞ったパッケージング検査を実行する。
変更を提示する前に、最終差分に意図したソース、テスト、文書、パッケージの更新だけが含まれていることを確認する。リリースまたは公開ターゲットはタスクが明示的に含む場合だけ実行し、意図的に範囲外とした広範な検査を報告する。
