unoh.github.com

JavaScriptのバグを退治する3つの手法

Tue Nov 21 21:35:12 -0800 2006



こんにちは、さかとくです。今日は、世界中のプログラマーを悩ませているバグを退治する方法について考えてみたいと思います。今回は、特に、JavaScriptのバグを退治する方法にスポットを当ててみたいと思います。

そもそも、バグ(Bug)とは、正しくプログラムが動かない状態、不具合のある状態です。
書き間違いや、なんらかの勘違いが原因であることが多いです。簡単なつづりミスならば、構文エラー(Syntax Error)によって、すぐに間違いが見つかります。しかし、簡単にバグの原因が特定できないことも多くあります。そんなときはどうしたら良いでしょうか?

以下の3点から考えてみます。

・具体的なデバッグ方法
・バグを予防する
・精神論


具体的なデバッグの方法

どんな天才的なプログラマーでも、間違いの1つや2つは犯してしまうものです。一度もバグに遭遇せずプログラムを完成させることはできません。「うまく動かない!どうしたら良いだろうか?」と慌てる前に、プログラムのどの部分が間違っているのか、特定することが一番大切です。

よくプログラミングの掲示板に「どうしてもバグが取れないんです。ソースをちょっと見てください。」と、長い長いソースがコピペされているを見ます。こういうのは、間違いなく「自分で何とかしろ!」と突っ込まれることになります。

とにかく、まずは、どの部分で処理が間違っているのか、ブレークポイントを設定したり、変数の値を確認してみましょう。JavaScriptなら、FireFoxのアドオンであるFireBugを利用することで、ブレークポイントを設定したり、変数の内容を見ることができます。※FireBugは便利すぎるので、使わないのはもったいないです。

また、IEでデバッグが必要なら、Visual Studioをインストールすると、Visual InterDev というのが入るので、これでステップ実行させることができます。(IEのオプションの詳細設定で、「スクリプトのデバッグを使用しない」をオフにしておきます。)

これらの、デバッガーを使うまでもない時は、alert("xxx") で変数の内容を確認したり、document.writeln("xxx") で処理の一連の流れを表示させるのが定石でしょう。

JavaScriptでよくはまるのが、メソッドが存在すると思って呼んでいるのに、綴りミスだったり、オブジェクト違いでメソッドが存在しなかったという場合です。怪しいと思うメソッドが存在するか、以下のようにしてチェックしてみましょう。


alert( object.method );


また、オブジェクトの内容を再帰的に表示したい場合がよくあります。そのときは、PHPのprint_r()に似た関数を作って使っています。


<script type="text/javascript"><!--
function print_r(obj) {
var count_obj = 0;
    function _output(str) {
       document.writeln(str + "<br/>");
    }
    function _print_r(obj, name, level) {
     var s = "";
        if (obj == undefined || level > 4) return;
        for (var i = 0; i < level; i++) { s += " | "; }
        s += " - " + name + ":" + typeof(obj) + "=" + obj;
        _output(s);
        if (name == "document" || typeof(obj) != "object") return;
        for ( key in obj ) {
        if (count_obj++ > 150) return;
         _print_r(obj[key], key, level + 1);
        }
    }
   _print_r(obj, "*", 0);
}
//-->
</script>


これなら、print_r( obj ); とやるとオブジェクトのプロパティ一覧を確認できます。

print_r.gif


バグを予防する

また、バグの原因を作らないようにするのも、最大のデバッグ方法だと言えます。プログラムをユニット単位に分割し、ユニットテストを行いながらプログラムを作ります。完成してからデバッグするよりも、テストファーストでテストをしながら作る方が、結果的には、短時間で完成することが多いようです。

JavaScriptの、ユニットテストライブラリ「JsTrester」や「JsUnit」を利用してみるのも良いでしょうか。

ただ、私はそれほど大きなプログラムをJavaScriptで組まないので、もっと単純に C言語にあるような assert() 関数を作っておいて、ファイルごとにテスト項目を作ってテストするようにしています。


精神論

また、時には、どうしてもバグの原因が分からず、精神論で勝負しないといけないこともあります。プログラミングに煮詰まってしまったら、一度、その場を離れて冷静になって考えなおしてみましょう。

煮詰まったときの対処方法として、私が一番効果があると思っているのは、プログラムの内容を誰か他の人に聞いてもらうことです。職場の同僚や友達に、とにかく処理の内容を聞いてもらうのです。

相手がプログラマーなら、プログラムの矛盾を指摘してくれたりするので、一番良いのですが、全くの素人だとしても、「ここがこうなって、こうなって…」と丁寧に説明していくうちに、怪しい点を見つけることができるでしょう。

他の方法としては、プログラムのソースコードを声を出して読んで見るのも、効果があるようです。このとき、ただ読むだけでなく、処理の流れごとにコメントを書き加えながら読んでいくと矛盾点を見つけることができます。

そして、究極の方法ですが「眠る」のが一番です。原因がつかめずムキになってパソコンに噛り付いているよりも、睡眠をとって、脳を休ませると、良い解決が見つかります。無駄な時間を浪費することもなくなります。私はよく夢の中でデバッグをしていることがあり、バグの原因を特定したところで目が覚めたこともあります。

それから、部屋をぐるぐる歩き回って考えるというのもよく聞きます。階段を上ったり降りたり、トイレに篭ってみたり、コンビニに飲み物を買いに行くなどなど、その人それぞれの効果的な方法があると思います。こうした方法は、他の人から見ると「奇行」なので変態扱いされることが多いのですが、なるべくカッコよくデバッグしたいものです。

頑張らないこと

とにかく、頑張ってプログラミングしていると、バグを作りこみがちです。

難しくてトリッキーなプログラムを作るのはバグの元凶となります。自分の能力や理解を超えた処理が必要なら、既存のライブラリを使いましょう。

若いころ、自動車の免許を取りに行ったとき、事故を起こさない最大の対処方法は、車に乗らないことだと言われました。プログラミングにおいても、時には自分で作らないことも大切だと思います。

また、誰が見ても、処理の内容が分かるプログラムを書きましょう。ちょっとダサくて冗長でも、バグに悩んで時間を浪費するよりは、ずっと良いはずです。力を抜いて頑張らないで作ることが大切だと思います。