Assert大好き

ソースコードの実装では、いわゆるDesign by contract(契約による設計)の考え方を取り入れて、処理の前には事前条件をassertで検査、処理の後も同様に結果を検証させるようにしている。値の範囲や文字列の長さ、nullポインタか否かという点などを片っ端から確認しているので、本来の処理前後に、asser文だけがずらりと並んでいたりする。

目的は単純で「中途半端な状態で処理を行わないこと」に尽きる。本来は許されないはずの中途半端な状態のまま処理が進んでしまうから、ずっと後になって問題が顕在化していまい、原因発生の箇所を特定するのが難しかったりする。そんな不毛な作業にうんざりした経験に懲りて、「少なくとも自分の担当範囲では問題がないことを証明する」ため、assertを積極的に使うようになった。これさえ使えば、問題な発生時にどちらに原因があるのか?という事実が極めて明確になる。

なお、publicな関数の呼び出しの場合、エラーの内容は呼び出し側に知らせてあげるのがAPI設計のマナーと聞いたことがあるが、広く配布するソフトならともかく、自分の目の届く範囲での開発では不要という気もする。そこまで親切に呼び出し側へエラー情報を教えてあげるような実装は、かなり面倒なのよね。Assertで問答無用に処理を打ち切る方が、かえって効率的だったりする。

また、「デバッグ時はassert有効、リリース時はassert無効」という話をよく聞くが、個人的にはあまり感心しない設定だと思っている。デバッグ時でもリリース時でもバグはバグでのはずだ。デバッグ時には補足するが、リリース時には補足しないというのでは、assertの意味が無い。問題ある状況なら、大きな問題がずっと後になって発生するよりも、見つかり次第速やかに表明させるべきだと思う(もちろん、このような処理を行って良いか否かは、対象システムの形態に大きく依存するけれど)。昔は、このような意見を言っても「少数派の考え方」と見なされることが多かったけれど、マコネル先生の本に同様の記述を見つけてからこの本を片手に考え方を説明するようになった。大きなソフト開発のバグに悩む人は、結局のところ同じような解決策に行き着くようですね。

たとえば、Microsoft Wordのソースコードでは、常に真であるはずの条件がアサートされるようになっているが、エラーはアサーションが失敗した場合に備えてエラー処理コードでも処理される。Wordのように、大規模で複雑な寿命の長いアプリケーションでは、アサーションは開発時のエラーをできるだけ多く暴き出すのに欠かせない。しかし、アプリケーションは非常に複雑で(数百万行のコードから成る)、改良を重ねてきているので、ソフトウェアをリリースするまでに全てのエラーが検出され、修正されると考えるのは現実的ではない。このため、製品版のシステムでもアサーションでエラーに対処しなければならない。

CODE COMPLETE 第2版 上 完全なプログラミングを目指して

CODE COMPLETE 第2版 上 完全なプログラミングを目指して