2005/08/27
バグを潜伏させない工夫 - バグをいかに目立たせるか
とにかく目立て
Be visibleリチャード・ブランソン
一般的にバグの発生箇所と発現箇所が離れれていると、デバッグは難しくなり、時間もかかりがちです。今回のお話は、このような「バグの潜伏」を抑制し、「バグ」にいち早く気付かせるための実装上の工夫についてです。
ライブラリ設計において、何らかのオブジェクトにアクセスするIDを定義することがあります。例えば次のような関数定義があったとします。
file_id_t open_file(const char* path, int flags); ssize_t read_file(file_id_t id, char* buf, size_t size); ssize_t write_file(file_id_t id, const char* buf, size_t size); off_t seek_file(file_id_t id, off_t offset, int whence); int close_file(file_id id);fileをオープンする関数によって返されたID(file_id_t型)が返され、以後のファイルアクセスはこのIDを介しての操作になっています。Linux等POSIX系システムで開発されている方はお気づきかと思いますが、上記の関数はPOSIXのI/O関連のsystem callのopen()/read()/write()/lseek()とほぼ同じ形をしています。POSIXでは、file_id_tに相当するのはint型のfile descriptor(fd)になります。POSIX系システムでは、ファイル以外にもsocketやデバイスドライバ等も同様のインターフェースでアクセスされます。POSIXで言えば、プロセスIDやユーザID等のIDもインターフェースに登場します
このようにopen等の関数で一旦捜査対象のIDを取得し、その後はそのIDで操作すると言うインターフェースは様々なところで見られます。このようなIDを用いたインターフェースの利点は何なのでしょうか?全てのインターフェースにファイル名等の文字列をそのまま用いる方法ではだめなのでしょうか?あるいは、IDではなくファイルオブジェクトへのポインタを返すというのでは駄目なのでしょうか?
IDを用いたインターフェースの利点は次のようなものが考えられます。
- int型等の単純な型を用いることにより、対象の発見コストが低い
(int型の比較と文字列方のstrcmpをイメージしてみて下さい) - IDの有効範囲を適切に設定すれば、プロセス間、システム間のやりとりが可能。
ポインタでは同一メモリ空間内でしかやりとりできない。
前振りが長くなりましたが、今回の話題は「IDにどのような値を用いるべきか」という点です。
多くの場合、IDは「特定のオブジェクトを一意に指すもの」として定義される程度で、その値が具体的にどのような値を持つかという点については外部仕様として定義されないことも多いかと思います。IDはマジックナンバーとして利用されるものですので、利用する側が特定の値を期待してはいけません。そう考えると、IDの値について定義しないというのは順当だと考えられます。
外部仕様としてはIDの値について具体的な定義はしないものとしたとしても、実装側としてはどのような値を持たせるべきでしょうか。外部仕様を満たすだけであれば、何でも良いでしょう。例えば、
- 0から順番にインクリメントした値を振っていく
- 利用されなくなったIDは再利用する
- 0は偶然利用される可能性が高い
- IDの再利用は、IDの取得/解放シーケンスにバグがあった場合に、複雑なバグをまねきやすい
- 特殊な値、(0,1は~1(0xffffffff)等)はIDとして使用しない
- IDは(極力)再利用しない
- IDは1インクリメントで生成せず、2や3インクリメントなどで生成する
どれも、偶然適当な値が入ることによって中途半端に動作が継続し、バグの発見が遅れたり、解析の手間が増えることを防ぐ効果があります。
と、ここまでIDの値という点で書きましたが、話の趣旨は次の二点に集約されます。
- 外部仕様に出ない部分でも、ちょっとした工夫をするかしないかでデバッグ効率は大きく変わる
- バグを含むコードであっても「偶然」や「なんとなく」で動作を継続させるとデバッグが難しくなる。 バグのある地点にできるだけ近い地点でバグに気付かせることで、デバッグ効率は上がる
ライブラリ設計において、機能性、拡張性、柔軟性等を考えることは勿論ですが、開発時にバグが混入し難い、バグ混入しても発見しやすい工夫といったことも頭に入れて置きたいですね。
【関連記事】
・デバッグ指向のススメ
コメント