自分の理解を深めるために投稿します。
第8章:防御的プログラミング
無効な入力に対して
良いプログラムは「ゴミ(無効な入力)」を入れてもゴミを出さない。
代わりに、
- 外部からのデータの値を全て確認する
- ルーチンの全ての入力引数の値を確認する
- 不正な入力の処理方法を考える
- エラー処理テクニック(後述)
アサーション
エラー:発生が予想される状況
アサーション:発生してはならない状況 に使う
- アサーションに実行コードは含まない
- コンパイルで問題が起こらないようにする
- 事前条件・事後条件の文書化と検証にアサーションを使用する
Private Function Velocity (
ByVal latitude As Single
...
) As Single
// 事前条件
Debug.Assert( -90 <= latitude And latitude <= 90 )
...
// 事後条件
Debug.Assert( 0 <= returnVelocity And returnVelocity <= 600 )
// 戻り値
Velocity = returnVelocity
End Function
- 堅牢性の高いコードは、エラーをアサートしてから処理する
エラー処理
正当性か、堅牢性か、どちらを重視すべきソフトウェアなのか考えて処理する
- 当たり障りのない値を返す(堅牢性)
- 無害だとわかっている場合
- 次に有効なデータで代用する(堅牢性)
- 前回と同じ値を返す(堅牢性)
- 無害だとわかっている場合
- 有効な値のうち、もっとも近いもので代用する(堅牢性)
- ファイルに警告メッセージを記録する
- エラーコードを返す
- エラー処理ルーチン/オブジェクトを呼び出す
- エラーが発生した場所でエラーメッセージを表示する
- ローカルで最もうまくいく方法でエラーを処理する
- 処理を中止する(正当性MAX)
例外
-
本当に必要な時だけ使う
- ローカルで処理できるエラーはローカルで
- 例外も抽象化レベルを揃える
- 例外メッセージに原因に関する情報を全て盛り込む
- 空のcatchブロックを書かない
- 例外レポート用ルーチンで一元管理する
バリケード
ダーティデータを扱う部分とクリーンデータを扱う部分を定義すること
- バリケードの外側ではエラー処理、内側ではアサーションという区別がつく
- 内側ではデータが綺麗になっているはずなので…
- 入力データは入力時に正しい型に変換する
デバッグエイド
デバッグエイド = デバッグを補助するツール
- 導入は早ければ早いほど良い
-
攻撃的プログラミングを利用する(運用での失敗が軽く済むように開発段階で失敗を重ねておく)
- アサーションを使ってプログラムを中止する
- 割り当てたメモリ全体をデータで埋め、メモリ割り当てのエラーを検出できるようにする
- オブジェクトを削除する直前にジャンクデータを設定する など
- デバッグコードの出し入れを繰り返す必要がない計画を立てる
製品コードに防御的プログラミングをどれくらい残すか
残すもの
- 重要なエラーを検査する部分
- プログラムを上品にクラッシュさせるコード
- テクニカルサポート担当者のためのエラー
- わかりやすいエラーメッセージ
削除するもの
- 些細なエラーを検査するコード
- 処理を中断させるようなコード