IDEのデバッガには、1行づつの「ステップ」、関数の中へ入る「ステップイン」、関数から戻る「ステップオーバー」、ローカル変数やメンバー変数の値を表示する機能があります。
「ステップイン」することなく、「ステップ」だけでどこを通っているかを確認できたり、関数の戻り値を確認できると、デバッグしやすいです。
式の一部分を指定して評価する機能もありますが、その操作をする必要があります。
以下の例は、javascriptです。
1行に1関数
1行に2つ以上の関数を書くと、2つめ以降の関数にステップインしにくいです。
デバッグしにくい例
func_a(); func_b();
Code language: JavaScript (javascript)
func_b内にステップインしたいとします。1回目の「ステップイン」でfunc_aにステップインします。func_a内から「ステップオーバー」でこの行に戻ります。2回目の「ステップイン」でfunc_bにステップインします。
デバッグしやすい例
func_a();
func_b();
Code language: JavaScript (javascript)
func_bの行で止まり「ステップイン」すると、func_b内にステップインします。
if文の条件と本体は別の行にする
if文の条件部分と本体を1行にすると、ifの本体を通ったのかわかりにくくなります。
デバッグしにくい例
if (1 < a) { func_a(); }
Code language: JavaScript (javascript)
ステップ実行すると、if文の条件のtrue/falseに関係なく、次の行に進みます。条件が成立したのか、しなかったのか、func_aを呼んだのか、呼ばなかったのか、がわかりづらいです。
デバッグしやすい例
if (1 < a) {
func_a(x);
}
Code language: JavaScript (javascript)
ステップ実行すると、if文がtrueなら、func_a()の行で止まります。
if文の条件を関数化する
if文の条件式が複雑だと、式内のどの条件がtrue/falseなのかわかりにくくなります。
デバッグしにくい例
if (x <= func_a() && y <= func_b()) {
}
Code language: JavaScript (javascript)
このif文が予想外の結果だとします。func_a()が予想外なのか、func_b()が予想外なのか、わかりません。
デバッグしやすい例
さきほどのifの条件文そのままなら、
function is_xxxx(x, y) {
var a = func_a();
var f1 = (x <= a);
if (!f1) {
return false;
}
var b = func_b();
var f2 = (y <= b);
if (!f2) {
return false;
}
return true;
}
if (is_xxxx(x, y)) {
}
Code language: JavaScript (javascript)
次の書き方は、if文をなくせます。ただし、微妙に意味が違います。
function is_xxxx(x, y) {
var a = func_a();
var f1 = (x <= a);
var b = func_b();
var f2 = (y <= b);
var f = f1 && f2;
return f;
}
if (is_xxxx(x, y)) {
}
Code language: JavaScript (javascript)
1つめの書き方では、x <= aが成立しないときは、func_b()は呼ばれません。
2つめの書き方では、x <= aの結果に関係なく、毎回func_b()が呼ばれます。
func_b()が副作用のある処理をしている場合、1つめの書き方と2つめの書き方で結果が違ってくるかもしれないので、要注意です。
関数の引数で、別の関数を呼ばない
関数Aの引数で関数Bを呼ぶと、関数Bの戻り値を確認しにくくなります。
デバッグしにくい例
func_a(func_b());
Code language: JavaScript (javascript)
func_bの戻り値を確認するには、func_aにステップインする必要があります。
また「1行に関数を2つ以上書くと、2つめ以降の関数にステップインしにくい」と同じように、func_bにステップインするまでの操作が多くなります。
デバッグしやすい例
var b = func_b();
func_a(b);
Code language: JavaScript (javascript)
func_a(b);の行で止まると、変数のbの値が表示されます。
return式で関数を呼ばない
return式で関数Aを呼ぶと、関数Aの戻り値を確認しにくい。
デバッグしにくい例
return func_a();
Code language: JavaScript (javascript)
func_a()の戻り値を確認できません。
デバッグしやすい例
var result = func_a();
return result;
Code language: JavaScript (javascript)
return result;で止まると、変数resultの値が表示されます。
多くのlintでは、ローカル変数 result は不要、と警告されますが、気にしないことにします。
1式1関数
1行1関数のバリエーションです。右辺の式内で2つ以上の関数を呼ぶと、戻り値を確認しにくいです。
デバッグしにくい例
var x = func_a() + func_b();
Code language: JavaScript (javascript)
func_aやfunc_bにステップインしないと、戻り値を確認できません。
デバッグしやすい例
var a = func_a();
var b = func_b();
var x = a + b;
Code language: JavaScript (javascript)
2行目まで進めば、変数aの値が表示されます。3行目まで進めば、変数bの値も表示されます。
最近のAPIの名前は長いので、1行で複数のAPIを呼ぶと、1行が長くなってしまいます。長い1行にしても、折り返したとしても、読むとき追いかけにくいです。1つづつAPIの戻り値を変数に代入すると、読みやすくなります
関数の戻り値は変数に代入する
1行1関数、1式1関数の究極バリエーションです。
デバッグしにくい例
var y = 123 + func_a();
Code language: JavaScript (javascript)
こんな簡単な式でも、これ以降の処理で想定外な動きがあると、次のようにyの値を表示して確認することになります。
var y = 123 + func_a();
console.log(y);
Code language: JavaScript (javascript)
yの値を表示してみたけど、予想した値ではない場合、さらにfunc_a()の値を表示して確認することになります。
var a = func_a();
console.log(a);
var y = 123 + a;
console.log(y);
Code language: JavaScript (javascript)
console.logを削除したものが、次の「デバッグしやすい例」です。
デバッグしやすい例
var a = func_a();
var y = 123 + a;
Code language: JavaScript (javascript)
あやしい動きのとき、各行の直後にconsole.logを書くことで、変数の値を表示できます。デバッガでステップ実行したときも値を確認しやすいです