Skip to content

Latest commit

 

History

History
82 lines (62 loc) · 6.3 KB

debug.md

File metadata and controls

82 lines (62 loc) · 6.3 KB

デバッグ

開発は、コードを書いている時間よりデバッグをしている時間のほうが長くなります。 デバッグの快適さは開発の楽しさにかなり直結します。 Rubyはこの環境が恐ろしく整備されています。

Rubyでのデバッグ

Rubyは、文化的にかなりみっちりテストを書きます。 特にRailsのような足元が整備されビジネスロジックだけに集中できるフレームワークの場合、一切アプリケーションを実行すること無く テストだけで開発できてしまいます。

テストは rspecminitest などを使いますが、 直接実行するよりも guard という ファイル監視ツール から実行できるようにすることがほとんどです。 Railsは規約が強いフレームワークなので、 app/controllers/users_controller.rb が更新されると対応するテストである spec/controllers/users_controller_spec.rb を実行したりもできます。

ここまで、基本的に一切の作業をすること無く rspec --initguard init だけでこの環境が作れます。

さて、テストが落ちた時Rubyistはどうするのでしょう。 なんと、おもむろにコード上に binding.pry と書きます。 するとどうでしょう、guard で回っているテストの該当箇所で REPL が起動します。

この pry というREPLが異常に優秀で、その場でRubyのコードが実行できるだけでなく、 ls x変数が持つメソッド一覧 を見たり、 $ x.fooメソッドの実装 を見たりできます。 メソッドの実装がその場で読めるのでデバッグに非常に役立ちます。 Railsなどの複雑なGemの場合、実装を読むだけではそれでも動きが理解できない場合がありますが、 そういう場合でも、Rubyはただのテキストファイルなので、手元にあるGemのコードに直接 binding.pry を書いてしまえば良いのです。

この binding.pryただのRubyのメソッド呼び出し なので、もちろんRubyの文法が自由に使えます。 例えば特定のケースだけでテストが落ちる時、

def foo(arg)
  binding.pry if arg == 100
  ...

と書けます。

他の言語にもこのようなデバッガのようなものは多々ありますが、Rubyの場合は非常に高度に独立していると言えます。 ただ binding.pry を書けばいいだけなので、特定のIDEなどのツールに依存しません。 多くの言語のデバッガは ブレイクポイント を設定するのにGUIを使わざるを得ず、だいたいIDEが必須になってきます。 それに比べRubyでは好きなエディタと好きなシェルだけで自由自在にデバッグできるのです。

また、多くの言語が デバッガからプログラムを起動する や、 デバッグモードでプログラムを起動する など少し特殊な方法でプログラムを起動するのに対し、 Rubyの場合はただのRubyコードなので、いつもと同じようにRubyを動かせばいいだけというのは大きな利点です。 すなわち、 ruby foo.rb でも、 rspec foo_spec.rb でも、 rake spec でも、guard の中でも、 はたまたRailsアプリにブラウザでアクセスしたときでも、どんなときでもその場で pry のコンソールに落ちます。 例えばJavaScriptには debugger という構文がありますが、ブラウザでは止まりますが node では止まりません。 Rubyは必ず同じ方法で同じように止まるのです。

他の言語の場合

JavaScriptのデバッグは、 ブラウザ という最も馴染み深いデバッガを使うところが最大の利点です。しかし、上述したようにテストランナーの中で止めることはできません。 実際コードを動かす場所はほぼブラウザであり、テストツールでブラウザを完璧にエミュレートしているわけではないので、最終的にブラウザで動かしてみる以上のデバッグは不可能なんじゃないかと思います。 また、メソッドの中身を見ようとしたら f () { [native code] } と言われて悲しい気持ちになることも多々あります。

JavaScriptの世界では、コードが変更されたら何かをするというのはかなり一般的です。 なのでテストやビルドを自動的に回し続けたりすることは可能です。 ただし、guard のように監視ツールがまとめて面倒見てくれるのではなく、ツールごとに --watch のオプションを実装しているパターンがほとんどです。

Pythonでは pdb というデバッガが存在するらしいですが使われているんでしょうか? 特に機械学習やデータ処理系の人は Jupyter Notebook というコードが実行できるドキュメントシステムを使うことが多いようです。 たぶん彼らは python コマンドの使い方を知らないんでしょう。

GOやJavaは昔ながらのデバッガを使うようです。 GOでは delve というのが人気らしいです。 PHPにはデバッグという概念は存在しません。

まとめ

Rubyはテストが書きやすく、テストを回しやすく、そして何より テストを止めやすい という点でデバッグ能力がめちゃめちゃ優れています。 いつも開発するときは binding.pry で止めてコード読むので、 型が必要だとかドキュメントが必要だとか感じたことが全然ありません。 その場でほとんどのコードにアクセスできるのは本当に快適です。 とにかく他の言語でも止まって欲しい。 止まって、中身を見せて欲しい。

一番の問題は避けては通れないJavaScriptです。 特に最近は トランスパイル難読化 が必ず行われるので、ソースコードを読むことが非常に大変です。 ブラウザでしかデバッグできないのに、ブラウザが読み込んでいるのは難読化されたコードという地獄に陥ったりします。 とてもつらい。