2005-09-22

[][]防衛的プログラミングで開発効率をあげるには(2) 防衛的プログラミングで開発効率をあげるには(2) - Nao_uの日記 を含むブックマーク はてなブックマーク - 防衛的プログラミングで開発効率をあげるには(2) - Nao_uの日記 防衛的プログラミングで開発効率をあげるには(2) - Nao_uの日記 のブックマークコメント

先日の日記で触れたような「問題が起こったときにエラーログを表示して防衛的に動作させるシステム」を導入することに関してチームの他のプログラマと話をしたときの反応は、おおむね次の3種類のどれかに分類できる

  • (1) そんなの面倒だし、パフォーマンスも落ちる。そもそもそんなチェックやエラー処理などは現実的ではないので不要!
  • (2) 言いたいことはわかるが、エラーログなど誰も見ないのでバグを握りつぶすコードを入れるくらいならassertで止めたほうが安全。
  • (3) 理想論としてはまぁわかるので、とりあえずやってみようか。

実際には説得が進むにつれて(1)->(2)->(3)と意見が変わっていく人が多いのだけど、それでもやはりなかなか納得してもらえない人もいる。

(1)(2)の立場をとる人から共通で受けるよくある反論として「バグが出ているにもかかわらず安全に動作させることなど不可能だし、意味がない」というのがある。たとえば「プレイヤーのデータがおかしくなっていてモーションが再生できない」などといった状態ではゲームの進行が不可能となるために続行しても意味がない、みたいなシチュエーションが挙げられる。しかし、実際にやってみるとほとんどの場合にはそれほど手間をかけなくても他人に迷惑をかけない程度に正常動作させることができるし、それが最終的な製品の安定性につながることも多い。

また、処理負荷に関しては安全性とパフォーマンスのトレードオフだろうから、コアなループの内側などの大幅に速度を低下させるような場所のチェックはプロファイラで計測したうえではずすことを検討してみてもいいだろう。しかし、ほとんどの場面ではこのようなチェックのコストは無視できるように思う。最適化を行いたいのならもっと先にやるべきことが沢山ある。

次に、(2)の立場の人からよく指摘される点として「エラーログがだだもれに垂れ流されると誰も見なくなるので、意味がないし危険。それならストップさせたほうがまだ安全だろう」というのがある。この反論はかなり的を射ている。エラーログが出る状況(本来ならストップにつながるような重大なバグや、契約プログラミングにおける契約違反)が日常的に行われて大量のログが吐かれて無視される状態になってしまうと、ログそのものが意味を成さなくなるために、ストップしてくれればすぐ発覚するような潜在的なバグを放置することになってしまう。実際に導入当初はこのような状況に陥りやすい。

この問題の対処としてはエラーにレベルを設け、本来チェックを行わなければストップに直結するような重大なエラーはストップバグと同レベルの危機感を持ってすぐに対処する、という意識付けをチーム内で徹底することと、軽微な警告はそれを必要とする人のところでしか出力されないようにするなどの運用上の工夫を行うことで、ほぼ回避できる。常にエラーログには何も表示されないクリーンな状態を維持し、エラーが出るときには画面のそれなりに目立つ場所に出して互いに報告しあって修正を促すことで「エラーを放置するのは悪」という空気さえ作れればエラーログのシステムを有効に活用することができるようになる。

assertでストップさせるよりも、そのまま処理が継続できたほうが便利なことは多い。チェックはなるべく厳めに行うべきだけど、軽微なミスでもいちいちストップしていたのではデザイナやプランナの人の作業に支障が出る。止めずに継続させることで同じバグを時間のかかる再起動をかけなくても何度でも再現させて調べることができるようになるし、エラー表示部分にブレークポイントを設置すればassertと同様にデバッガで追うこともできる。この場合、ゲームはまだ動作中なので完全にストップしている状態よりも状況を調べやすいというメリットもある。

また、逆に考えてみると大量にエラーログが出る状況というのは、このようなチェックを入れなければそれだけの契約違反が日常的に行われているという証でもあるので、それがどれほど恐ろしいことなのか実際にやってみるとよくわかると思う。考え方としてはコンパイラの警告レベルを最大に上げてWarningをなくそう、という試みと似たところがあるかもしれないけれど、有効に機能すればこちらのほうがはるかに効果は高い。前回の仕事からこのようなエラーログのシステムを本格的に導入してみたのだけど、この対処がなければ潜在化していたであろう問題を早期に発見することで再現性の低いバグを減らし、システムを安定性をあげることで開発効率の向上に貢献することができたように思う。ログ表示のシステムはエラーの出力だけでなく、オブジェクト同士のメッセージのやり取りやエフェクト・SEなどの呼び出し履歴を取るなどの用途にも使え、応用範囲は広い。他社のゲームの実行ファイルをバイナリエディタで覗いてみると同様のエラーメッセージが残されているのを時々見かけるので、細かい方法論は違えども似たような処理を行っているところも多いのかもしれない。

あとは、半ば避けようのない問題として「エラーログの文字列や、エラー処理そのものが実行ファイルのサイズを増大させてメモリを圧迫する」というものがある。マスター版では文字列部分が削除されるとはいえ、家庭用ゲーム機では実行ファイルのサイズが制限されることも多いので、開発中バージョンでもメモリが足りなくて困ることが多い。これに関しては、次世代では搭載メモリが増えているので無視できるほど小さいコストになっているだろう、ということに期待したい。