防衛的プログラミングと契約的プログラミングの違いがイマイチ分かっていない
- 続編記事 : 契約による設計・契約プログラミングが少しワカッタ
防衛的プログラミング、防御的プログラミングとかいう手法と、契約による設計だとか契約的プログラミングとかいう手法があるらしい。が、イマイチその違いが分からない。概念的な話ばかりで、コードに落とし込んだ時にどういう違いが出るのかを説明してくれている文献があまり見当たらない。
いくつかの文献を見てみて僕なりの解釈をしてみたが、しっくり来ていないので誰か教えてほしい。
僕の防衛的プログラミングの解釈
- 呼び出し元も呼び出し先も関係なく、「この変数は null でないこと」「このファイルは必ず存在すること」といったチェックをしている。
- 例外が発生してもその場でプログラムが止まらないよう、エラーを握り潰すような作り。
- あらゆる箇所で「バグが起こらないように」とチェックしまくるイメージ。
僕の契約的プログラミングの解釈
- 引数と戻り値に明確な仕様を決める。チェック処理はメソッド自身の In と Out に留まる。
- 契約事項はアサーションでチェックする。引数のチェックと、実装の最後で戻り値をチェックする。守られていなかった場合は AssertionError 例外を投げる。
- アサーションは本番ビルド時は削除される。
- テストファーストで UT によって、あらゆる引数から戻り値を検証する方法もある。
- メソッドの使い方を知らない人が使った時に、適切な例外を投げるイメージ。
僕のコードで比較する両者の違い
防衛的プログラミング
function readFile(path, fileName) {
if(!path) {
throw new Error('Illegal Path');
}
if(!fileName) {
throw new Error('Illegal File Name');
}
let result;
try {
result = fs.readFileSync(path + fileName);
}
catch(error) {
throw new Error('Could not read file');
}
if(!result.text) {
throw new Error('Illegal File');
}
return result.text;
}
// 利用側の処理
const path = getPath();
if(!path) {
throw new Error('Path is null');
}
const fileName = getFileName();
if(!fileName) {
throw new Error('File Name is null');
}
const result = readFile(path, fileName);
なんていうんだろう、防衛的プログラミングは、「そのバグが起こりうるのは知ってましたから!対策ありますから!」みたいなイメージかなと思った。だから、throw new Error()
の部分は、要件が合えば「上手くいかない場合は空文字を返す」みたいな作りにしても良いのかなーと思った。
で、呼び出し元の方でも、引数として渡す変数のチェックをしていたりして、冗長だけど絶対に「予期していないエラーはない」状態にすることが、防衛的プログラミングかなと思った。
契約的プログラミング
function readFile(path, fileName) {
assert(!path);
assert(!fileName);
const result = fs.readFileSync(path + fileName);
assert(result.text);
return result.text;
}
// 利用側
const path = getPath();
const fileName = getFileName();
const result = readFile(path, fileName);
契約的プログラミングは呼び出し元でのチェックはせず、呼ばれた側が、自メソッド内で入力値チェックと出力値チェックをして終わる感じかなと思った。チェックもアサーションを使うのが特徴的というか、開発時だけエラーが検知できていれば、本番コードからはそのチェック仕様は取り除ける作りなのかな?と思った。
なんか勘違いしてそうなので、ご指摘賜りたく。
- 続編記事 : 契約による設計・契約プログラミングが少しワカッタ
参考
- 契約的プログラミングと防衛的プログラミング - 思い悩むblog 改め Buriに片思い日記
- 勉強部屋 — 防衛的プログラミングと契約的プログラミングは何が違うのか
- 防御的プログラミングしない後ろ向きの理由 : 柴田 芳樹 (Yoshiki Shibata) : So-netブログ
- 防衛的プログラミングと契約による設計 - ABAの日誌
- 防衛的プログラミングと契約による設計(メイヤーの定義) - 徳丸浩のtumblr
- 防御的プログラミング(CodeCompleteのまとめ)
- 再度、契約による設計と例外について
- とある契約の備忘目録。契約による設計(Design by Contract)で信頼性の高いソフトウェアを構築しよう。 - Bug Catharsis