デバッガを使うのは効率がよいのか

こういう話です:

以下の記事に以前書いたことがあったけど、別な話題を1つの記事に混ぜていると後から参照しづらいため、独立した記事に起こしただけで、とくに新しい話はありません。

この記事はEmacsdap-mode (debug adapter protocolのためのプラグイン)をScalaで有効にする方法を書いたもので、しかしそれは本当に要るのか? という疑問があります。

デバッガは本当に使うのか

テストの単体実行は(debugではなくrunの方で)毎日使ってるけど、dap-modeのデバッガは正直まだ一度も役立ったことがないですね。プログラミングを初めてしたのはVisual C++ 6.0上だったので、ステップ実行してローカル変数の状態を確認しながらデバッグできるのが初学者にとって役立つのは重々承知しているものの、職業ソフトウェアエンジニアをやっていて思うのはデバッガによるデバッグは、なんというか遅い。個人的にはデバッグ方法は以下の順で早いと思っています。

  1. 念力デバッグ
    • 現象だけを見て、コードを全く見ないでバグの原因箇所を当てる
      • 「あそこのコードがこうなってたら、このバグを引き起こすよね」という仮説を立てる
      • 実際そのコードを見に行って「ほらやっぱりこうなってるからこれダメだよね、直そう」とやる
      • (原因箇所を当てるのだけやって、コードの確認と修正を他人に任せるのが真の念力)
    • 熟知したコードベースのシステムに対してしかできない
  2. コールドリーディング (本来の意味とは違うと思うけど自分の頭の中でこう呼んでしまってる)
    • コードだけ読んで、実行はせずにバグの原因を特定する
    • 「コールド」というか静的
  3. printfデバッグ
    • 関係ありそうな値を根こそぎ出力しておく
    • 実行し終わった後で落ちついて一つずつ見ていっておかしくなる箇所を探す
    • ログレベルDEBUGとかでいろいろ吐くようにしておいてそれを眺めるのも含む
    • DBに投げてるSQLをぜんぶ出力する等
  4. デバッガで追う

デバッガを使う場合、まずポチポチするのが遅い。ブレークポイントで止まったけど、ああ、この回じゃなくてもっと後で同じメソッドが呼ばれる時にたぶんおかしいんだよな、うげぇ、行きすぎた、もっかいやろう、えーとこの変数がこうなってるからもうちょっと先でダメになるんかな、あ゛あ゛あ゛タイムアウトしたやんけ、やり直し...... みたいになるんですよね。僕だけかな。使い方が下手なんだろうとは思うけど、やってるうちに「あー、もう、鬱陶しい! こんなん、関係ありそうな値をぜんぶ出力しておいて実行し終えてから見たったらええねん!」とキレてしまう。

うまく使えばきっとprintfデバッグより効率よかったりするんだろうけど、それでも原理上、念力デバッグとコールドリーディングより早いことは絶対になくて、仕事で長くメンテしているシステムのデバッグをするときなんかはだいたいそれで済んでますね。

実際に使いそうな場面

もちろん全く使わないわけではなくて、最近だとたとえばrenovateにpull requestしたときに、挙動がよくわからなくて意図通りにいかなかったのでデバッガで追いました(ただ、Node.js環境をdap-modeでデバッグするのがうまくいかず、ブラウザからデバッグ用のポートに接続するやつでやってしまった)。

まぁいざというときのために使えるようにしておくに越したことはないとは思います。

デバッガを使いこなしててそっちの方がだいたい早く済むっていう人がもしいたら、逆に話を聞いてみたい(デバッグしてる様子を隣で眺めてみたい)。

https://twitter.com/oarat/status/1508325821882150912