テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(dm-lc report) エラー処理を実装していて思ったこと

ソフトウェアをまともにするために, エラー処理は不可欠であるということは明らかである. ではなぜか?

dm-lcは今まで, エラー処理をかなりいい加減に実装していた. まともに実装し始めたのはクマーのパッチからで, 今日は明らかに魔境のresume cacheもエラー処理を実装し, その他も一気にやった.

なぜエラー処理を書かなければならないのか, それは本質的ではないはずである. その通り, エラー処理などはなくても測定は出来る. しかしソフトウェアとしては未熟かも知れない. ある程度実装が固まってきた今が, エラー処理の書き時であろう.

エラー処理を書かなければいけない理由のもっとも大きなものは, 「ソフトウェアが誤った状態で動くことを防ぐこと」である. これは, 計算機リソースの上で動き続けるカーネルであれば当然として, 一般的なアプリケーションでも, 「何か結果は出力された, しかしそれが正しいかどうかは神のみぞ知る」という状況で良い場合と悪い場合がある. ユーザランドにおいては, ソフトウェアが誤った状態で動作しても, カーネルの場合ほどは悪くないだろうが, それがデータベースなど基幹的なミドルウェアであれば, 色々と破滅を来して人が死ぬ可能性もある. だから, 初期化コードなどでは入念にエラー処理をすべきである. 実は誤って初期化されていたけどなんとなく動かしちゃったは洒落にならない. メモリ確保などでは, 「確保出来るまでリトライする」などの手法によって, エラー処理を閉じ込めることが出来るだろうが, 初期化ごときでこういう扱いをされては困ってしまう. ユーザは, まだ導入してもいないソフトウェアがシステムを停止させることを嫌うだろう. しかし幸いなことに大抵の場合, 初期化コードというものには並行性がなく, 逐次的なので, エラー処理を書くことはそれほど難しくない. 難しいのであれば, そもそも設計が悪い.

ここまでは誰でも分かるのだが, 私はさらに「状態が狂わないのであればエラー処理は必要ない」と考える. 何でもかんでもエラー処理をしなければならないなどということは全くないでしょう.

エラー処理は, 場合によっては大域的な情報を放浪させるハメになるかも知れない. これは当然, 設計を乱す. そして, 正常パスをもバグりやすくする. エラー処理が局所的に収まるものであれば, やればいいと思う. なぜならば, このような単純なエラー処理では正常パスがバグったりはしないからである. 従って, やらないよりやった方がいい場合が多いからである. しかし, そうでなく, 複雑な技法を導入しなければエラー処理しないのであれば, 「状態がおかしくならないこと」を至上命題として, コードをシンプルに保った上で, ダメになったら再起動するくらいの運用を要求した方が良いこともあろうと思う. 何でもかんでも, 失敗をクライアントに返すことは不可能であるし, 無意味である. やばいと思ったらシステム自体を停止する方が良い場合もある. 「下手にエラーを返してシステムを続行させたが故に破綻する」ということは, そのエラー返しが技巧的であればあるほど確率が上がるだろう. また, 正しく初期化されたあとであり, 計算機環境がある程度まともであれば, 例えばメモリ確保に失敗したりI/Oが全く出来なくなったりということは発生しにくいだろう. むしろ電断などの方がリスクが高い. 計算機の故障については, ハードのレベルで冗長化させるべきであるとか, そういう考え方もふつうである.

だからdm-lcは, 初期化については, 失敗はユーザランドに返すことにしたが, 実行中はそんなことはしない. dm-lcは複数のスレッドが複雑に並行的に動くことによって最高性能を目指す設計になっており, 何かのエラーをクライアントに返すことに意味があるとは到底思えないし, 通常は局所的にリトライし続けるか, ダメなら閉塞させる方がシンプルだし確実である. 一番恐ろしいのは, システムが停止してしまうことではなく, ユーザのデータが消滅することである. dm-lcはライトバックキャッシュであるから, ユーザはこの点に対してもっとも敏感となる.

その他, エラー処理を書いていて気づいたのは, コードが綺麗になるということだ. 実際に, エラー処理を追加することによってコードの順序はより理路整然となった. コードがある程度固まったらエラー処理を追加するということはこの点でも意味があると思う.