JavaScriptのデバッグ方法 – JSを嫌いにならないためのTips

この記事のオリジナルは voxxedに投稿されたものです。

JavaScript関連の問題を抱えるチームをサポートする仕事を通じて、いくつか共通の問題点があることに気づきました。もしあなたもJavaScriptに対するイライラを感じているのであれば、この記事は何らかの助けになるかもしれません。おことわり:私がお教えするヒントはすでにご存知のものもあるとは思いますが、うまくいけば、多少なりとも有用な情報があるかもしれません。特にエンタープライズアプリケーションやCMSソリューションを構築する際に有効なヒントです。チームの誰もが話したがらないCMSのコードについてお話しします。いずれも必要に応じて採用できるものです。

debuggerステートメント

大半のブラウザでサポートされているにもかかわらず、JavaScriptを書く際に最も活用しきれていない機能の1つです。debuggerステートメントは、ECMAScript第1版から標準化されているため、かなり前から存在していることになります。

基本的にはブレークポイントを追加するという単純な方法です。ループ文を使った要素リストを実行する場合を見てみましょう。

ループ内にdebuggerステートメントを追加すると、処理を繰り返すたびにブレークポイントで止まります。

コードを実行すると、ブレークポイントを追加した場所でトリガが発生します。debuggerハンドラがない場合、例えばデベロッパーツールが搭載されていないほとんどのブラウザでは、このステートメントは効力を発揮しません。

デベロッパーツール側では手動でブレークポイントを配置したものと認識されます。

当然、本番用のコードに残しておきたいものではありません。ただ、これは開発中においては非常に便利な機能です。私にとっては人生が変わるほどの、特にコールバックが頻繁に行われるベンダーのJavaScriptコードを扱う際には役立つ機能です。

ルークよ、コンソールを使え! 

開発者のほとんどがデバッグの目的でconsole.logを使用します。しかしconsole.warnconsole.errorconsole.infoについてはご存知でしたか? 

いずれも以下のようなC言語で使われるような出力フォーマットをサポートします。

console.log("Hello %s", "Brian");

JavaScriptにはロギングフレームワークも多くあります。適切なロギングは、ほとんどのプログラミング言語において重要であり、JavaScriptにおいても例外ではありません。全てのロギング機能が標準化されているわけではなく、フォールバックが必要となるブラウザもあることに注意してください。こちらに現実問題としてのロギングに関する詳細記事がありますので、参考までにご覧ください。

console.table()を使ったJavaScriptオブジェクトの概要

私たちは、さまざまなサービスからデータをロードしますが、特にそのデータがオブジェクトのリストであるような場合は、コンソール上でより見やすく表示できたらと思います。例えば、openbeerdatabase.comからビールのリストをロードする場合を見てみます(この素晴らしいデータは実在します)。 http://openbeerdatabase.com/documentation/beers-getにあるHTTP GET/beersをコールして、オブジェクトのリストを受け取ります。リストを受け取った後は、console.logを使って出力するだけです。

コンソール内で結果のリストをうまく閲覧するのは困難です。データが示すものを明確に把握しづらいのです。データ全体を見るのも面倒です。JavaScriptオブジェクトであるどんな大きさのリストについても同じことが言えます。

console.logをconsole.tableに置き換えて再度コールすると以下の通りに出力されます。

ご覧の通り、結果はテーブルで出力され、オブジェクトの属性でソートすることができます。一覧するのも楽になります。例えば、次の方法で2つの配列を、視覚化して簡単に比較することができます。

console.table([[1,2,3], [2,3,4]]);

さらに多くの配列が含まれている場合でも、この方法を使えば見やすい結果が出力されます。

コールトレースを取得する

コールトレース、つまり”誰が私の関数を呼び出しているか”を知りたい場合があります。コールとレースは私たちがなにか失敗した時に見られるものですが、console.traceを使用すれば、失敗した時だけでなく、成功した時にもコールトレースを確認することができます。

console.traceは非標準の関数であり、本番のコードに残すものではないことに注意してください。そうは言っても、主要なデスクトップブラウザではサポートされています。
非同期コールを実行するTraceConsole.traceは通常の関数呼び出しでは正常に機能します。ほとんどのデベロッパーツールでは、ブレークポイントで停止したときに同様のコールトレースを取得します。関数呼び出しが非同期(コールバック)の場合は、クロージャ(コールバック関数)のスコープが限られるため、この情報は取得できません。幸い、Chromeのデベロッパーツールの新バージョンにはAsyncのチェックボックスがあります。関数呼び出しの情報は、以前は次のように一部しか確認できませんでしたが…

新バージョンでは、呼び出し元とコールバック全てを含むコールトレースになりました。

個人的な意見としては、今日のような非同期処理が溢れた世界の中では、最も重要な機能だと言えます。非同期コールトレースがどのように機能するかについてはこちらのHTML5rocksの記事をお薦めします。

誰がオブジェクトを変更するか?: Objects.observe + console.trace

オブジェクトのプロパティの一部が変更されることがありますが、私たちにはその原因が分かりません。このような場合Object.observeが役に立ちます。personオブジェクトに対する全ての変更を確認する場合を見てみましょう。

console.traceと併用すると、コールトレースも確認できるのです。素晴らしいですよね? 

いや、それほどでもありません。これを書いている今現在、Chromeのみがこの機能をサポートしており、非標準機能です。幸いEMCAScript第7版の一部として提供はされています。Geckoベースのブラウザには、よく似た実装としてobject.watchがあります。ここでもまた、デバッグに関して言えば、取得できるものは何でも有用であると考えてください。Objects.observeの第一の用途はデバッグではありませんが、素晴らしい効用があるのです。

誰がDOMやHTML要素を変更するのか。つまりコードをめちゃくちゃにするのは誰だ? 

複雑なアプリケーションでは、HTML要素がどのように変更、移動、追加され、属性が修正されたのか分からなくなってしてしまうことがあります。そうした変更を検知する方法の1つに、今はもう非推奨となったMutation Eventリスナを使う方法があります。変更を検知するAPIは理想からほど遠い上に、他にもいろいろと欠陥があります。新しいバージョンのブラウザにはMutationObserverと呼ばれるオブジェクトがあり、これによってDOM要素の監視が可能になります。

ドキュメント全体で発生した全ての変更をリストアップしたい場合を考えてみましょう。この場合、ドキュメントは選択されたどのDOM要素にも当てはまります。

Chromeでは、プログラミング以外の解決策も使えます。DOM Breakpointsと呼ばれるもので、バックグラウンドでは依然としてMutation Eventを使っています。

サーバ側でクライアントのエラーログを取る

実に簡単なのですが、Windowオブジェクトにonerrorイベントハンドラを追加するだけでクライアント側の処理は完了です。ハンドラは、サーバ上にエラー情報を蓄積するRESTのエンドポイントに対してAjaxリクエストを行うことができます。IE9より前のバージョンにはstring.trim()が無いので、クライアントがIE8を使っている場合は、この方法ではいろいろと問題が多いと思う方もいるでしょう。string.trimはそれほど重要ではないと思います。

いずれにせよ、サーバ側でクライアントのエラーログを取るこの最も基本的な方法は以下のようになります。

もちろん、これは最も基本的な解決策です。もっと良い解決策がhttp://www.stacktracejs.com/http://jsnlog.com/といったサイトにたくさんあります。Mozilla hacksには豊富な手法が載っています。Hacker Newsという素晴らしいサイトでも、このテーマでディスカッションが行われています。いずれにせよ、この基本的な解決策は、スタートとしては良いと言えますね。

Googleや他の分析ツールを使ってデータを収集する

バックエンドのコーディングをする時間も無いほど忙しいというあなた。それなら、Google Analyticsにデータを収集してみてはどうですか? 

確かにこれならできますね。ただしこれは、とりあえずの手段です。徹底的に行いたければ、例えば他にもhttp://usersnap.comなど、もっと優れた多くの製品から選ぶことができます。でも、お手軽な方法だって何も情報が無いよりはマシです。何も情報が無い人がほとんどなのですから。

JavaScriptは”本物の”コードではないのか? 

I do not use debuggers, I stare at the code until it confesses
俺にデバッガはいらない
コードが尻尾を出すまで見張り続ける

私はこのことについて長年考えてきましたが、数年前、JavaScriptへのアプローチが全く間違っていることに気づきました。JavaScript に対しても、JavaやC#やRubyなどと同様に真剣に向き合うべきなのです。

病気になることを避けられないように、JavaScriptを学ぶことも避けられません。

他のプログラミング言語と同じように、JavaScript を使う人はやプログラミングの練習、複数のプロジェクトでの経験が必要です。そしてJavaScript自体にも、コーディングスタイルガイドやフレームワークのテストや、コード分析などが必要です。基本的に”本物のコード”に向き合う際に必要なもの全てが必要なのです。統合的にサポートしてくれるYeomanJHipsterといった完全な解決策もあります。

こうしたことを何もしないでいると、あなたは必ずJavaScriptを大嫌いになってしまうでしょう。JavaScriptは周り中にあふれているというのに残念なことです。ベストプラクティスに従えば、コードのデバッグに時間をかけることも、手のこんだコツに頼ることもなくなるでしょう。あなたがチャック・ノリスでなければ、ですが。

さらにこちらのサイトも参考にしてください

https://github.com/DeveloperToolsWG/console-object/blob/master/api.md
https://developer.chrome.com/devtools#debugging-JavaScript
https://developer.mozilla.org/en-US/docs/Tools/Debugger
http://msdn.microsoft.com/en-us/library/dd565625%28v=vs.85%29.aspx
https://developer.mozilla.org/en-US/docs/Web/JavaScript
www.HTML5rocks.com