cc-defensive-programming について
防御的プログラミングの実践状況を確認し、一貫した適用を支援するスキルです。境界での入力検証、アサーションの使い分け、明示的なエラー処理を重視し、レビューと実装の両モードを備えます。
主な機能
- 01入力検証と例外処理の確認
- 02空の catch ブロックの検出
- 03アサーションと実行時処理の区別
- 04入力検証境界の設計
- 05一貫したエラー処理方針の適用
活用シーン
- 01防御的プログラミング違反のレビュー
- 02外部インターフェースへの検証追加
- 03アサーションとエラー処理規則の策定
- 04非同期処理の失敗対応の改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ryanthedev/ code-foundations --skill cc-defensive-programmingインストール後、Claude Code で/cc-defensive-programmingを入力して読み込まれたか確認します。
同梱ファイルchecklists.md
詳細
cc-defensive-programming
防御的なコードは、小さな失敗が積み重なって、気づきにくく診断困難な問題になるのを防ぎます。以下の4つのチェックでは、目立つクラッシュを起こすのではなく、データを破損させたりバグを隠したりする違反を検出します。いずれもほぼ常に必要です。例外を認める場合は、明確な正当化が必要です。
| チェック | 理由 |
|---|---|
| アサーション内に実行可能コードを置かない | アサーションは本番ビルドではコンパイル時に除外されるため、コードも一緒に消えてしまいます |
| 空の catch ブロックを作らない | バグを黙って飲み込み、後続でより深刻な失敗を引き起こします |
| 外部入力を受け取り時に検証する | 未検証の入力は、セキュリティ上の脆弱性やデータ破損につながります |
| アサーションはバグにのみ使う | 想定されるランタイムエラーには、アサーション(本番環境では無効化される)ではなく、エラー処理が必要です |
共有のしきい値と情報隠蔽の根拠については、Read(${CLAUDE_PLUGIN_ROOT}/references/cc-foundations.md) を参照してください。
教科書のルールに優先する2つのルール
- 「チーム内部の API」も外部として扱います。 ネットワークまたはプロセスの境界を越えるデータは、すべて外部入力です。自チームが所有するサービスからのデータであっても、検証してください。
- バリケードによって冗長な検証を減らせますが、多層防御の代わりにはなりません。 バリケードの内側では、データが検証済みであると想定できます。ただし、セキュリティ上重要な経路(認証、暗号処理、PII)では、再度検証してください。バリケードの検証にもバグはあります。
外部入力とは、現在のコードパスによって制御されていると証明できないすべてのデータです。ユーザー入力、ファイル、ネットワーク/API/DB の応答、環境変数、その他のサービスからのデータが含まれます。
適用しない場合
- 副作用のない純粋関数(ただし、システム境界では引き続き入力を検証してください)。
- エラー対応の方針を決める前に、時間を区切って作成するプロトタイプ/スパイクコード。
- テストコード。本番環境のパターンに意図的に従わないテストダブルを使用します。
- アサーションのオーバーヘッドがプロファイリングで 5% を超える、パフォーマンスが重要な内部ループ。
上記にかかわらず、セキュリティ上重要なコード(認証、認可、暗号操作、PII の取り扱い)は、決して免除されません。迷った場合は、検証してください。
モード
CHECKER
防御的プログラミング、アサーション、例外処理のチェックリストに照らしてコードを確認します。Read(${CLAUDE_SKILL_DIR}/checklists.md) を参照してください。各項目につき1行を出力します:| Item | Status | Evidence | Location |。status は VIOLATION(検証の欠如、空の catch、副作用のあるアサーション)/WARNING(一貫性のない処理、ドキュメントの不足)/PASS のいずれかです。
APPLIER
アサーションの配置、エラー処理の方針、バリケードのアーキテクチャ、検証の実装を提示します。既存のエラー処理パターン(例外、戻りコード、Result 型、カスタム例外クラス、ログの規約など)をコードベースから探し、それに従ってください。エラー処理の一貫性が、失敗のデバッグを容易にします。完全なゲートについては、Read(${CLAUDE_PLUGIN_ROOT}/references/pattern-reuse-gate.md) を参照してください。
アサーションとエラー処理の使い分け
| 条件 | アサーション | エラー処理 |
|---|---|---|
| 決して発生しないはずの状態(プログラマーのバグ) | はい | いいえ |
| ランタイムに発生する可能性がある/想定される不正な入力 | いいえ | はい |
| 外部入力 | いいえ | はい — 必ず検証する |
| 内部インターフェース、同一モジュール内 | はい | いいえ |
| 信頼境界を越える内部インターフェース | はい | はい |
| 公開 API の事前条件違反 | はい | はい |
| セキュリティ上重要/高い堅牢性が求められるシステム | 両方 | 両方(多層防御) |
条件が本当に曖昧な場合(「これはバグか、想定された動作か」)、推測せずにドメインエキスパートに要件を確認してください。
正確性と堅牢性
- 正確性 — 不正確な結果は決して返しません。誤った回答を出すくらいなら停止します(安全性が重要なシステム、金融、データパイプライン)。
- 堅牢性 — 結果がときどき不正確でも、動作を継続します(コンシューマー向けアプリ、社内ツール)。
| 分野 | 重視するもの | 重要な問い |
|---|---|---|
| 安全性が重要な分野(医療、航空) | 正確性 | — |
| エンタープライズ/B2B、金融、データパイプライン | 正確性 | 誤ったデータが不適切なビジネス上の判断につながりますか? 下流のシステムはデータの完全性を前提としていますか? |
| SaaS プラットフォーム | バランス | 誤った回答の影響範囲と、利用不能による影響のどちらが大きいですか? |
| コンシューマー向けアプリ、社内ツール | 堅牢性 | ユーザーはクラッシュから復旧できますか? |
| リアルタイムシステム | 状況による | 古いデータは、データがない状態より望ましいですか、それとも望ましくないですか? |
バリケード設計
- 外部インターフェース(ユーザー入力、ファイル、ネットワーク、API、サービス間呼び出し)を特定します。
- バリケードの境界に検証を配置し、すべての外部データをここでチェックします。
- バリケードの内側では、内部バグにアサーションを使います(データは検証済みであると想定します)。
- 方針:外部境界ではエラー処理、内部ではアサーションを使います。
クラスレベルのバリケード:パブリックメソッドは検証とサニタイズを行い、クラス内のプライベートメソッドは安全なデータを前提にできます。
エラー処理の方針
いずれかを選び、一貫して適用します。エラー処理はアーキテクチャ上の決定事項です。
| 方針 | 用途 |
|---|---|
| 中立的な値を返す | 表示用のデフォルト値、重要度の低い設定 |
| 次に有効なデータに置き換える | 冗長性のあるストリーミングデータ/センサーデータ |
| 前回の回答を返す | 表示の更新、重要度の低いキャッシュ(金融データでは決して使わない) |
| 最も近い有効な値に置き換える | 入力値のクランプ、スライダーの範囲 |
| 警告をログに記録して続行する | 重要度の低い機能低下、機能フラグ |
| エラーコードを返す | ステータス規約のある API、C スタイルのインターフェース |
| 集中型エラーハンドラー | 一貫したログ記録、監視との統合 |
| エラーメッセージを表示する | ユーザー向けアプリ(セキュリティ情報を漏らさない) |
| 正常にシャットダウンする | 安全性が重要なシステム、データを破損させるエラー |
最新のエラー伝播
同期的な例外伝播は同期的なコールスタックを前提としています。次のパターンでは明示的な処理が必要です。
- async/await — 未処理の拒否は Node をクラッシュさせます。await する呼び出しをラップし、ドメインレベルの例外を再スローします。
- コールバック — エラーは伝播しません。エラーを先頭に置く
callback(error, result)パターンを使うか、Promise でラップします。 Promise.all— 最初の拒否が発生すると、ほかの結果は失われます。allSettledを使い、全体を失敗とするか、一部の結果を許容するかを判断します。- イベントハンドラー/React — 同期的なスローは黙って握りつぶされます。明示的にログを記録し、レンダーエラーにはエラーバウンダリーを使います。
攻撃的プログラミング(開発ビルド)
開発中はエラーが早期に見つかるよう顕在化させ、本番環境では適切に復旧して目立たないようにします。手法:アサーションでプロセスを中断する、割り当てたメモリや解放済みオブジェクトをジャンクデータで埋める、default/else 節で即座に失敗させる、エラーログを自分宛てにメールする。
根拠
- 「ゴミを入れればゴミが出る」は時代遅れです。製品版ソフトウェアは検証するか、データを拒否しなければなりません[McConnell p.188]。
- エラー処理はアーキテクチャ上の決定事項であり、一貫して徹底されます[McConnell p.197]。
- バグの修正コストは、設計時に比べて本番環境では約100倍になります[IBM Systems Sciences Institute]。
- Mars Climate Orbiter は単位の不一致により失われました[NASA 1999]。9か月間の成功は、コードが安全であることを意味しません。
次のステップ
| 現在の状態 | 次 |
|---|---|
| 検証完了 | Skill(code-foundations:cc-control-flow-quality) |