printデバッグについて

初心者が多用するデバッグ法というと、printデバッグです。誰に教わることもなく、自然と自己発見して使い続けるケースが多い気がしています。

プログラマーの三大美徳には怠惰という文言があります。ただ、この怠惰というのは繰り返し作業をやめるために、アクティブな行動を伴うので、別なポジティブなラベリングがされるべきだし、個人的にはちょっと違和感があります。低きに流れて部分最適化されてしまうprintデバッグこそ愛すべき怠惰な気がしています。

UI/UXというと、すごい意識高い感じだけど、じつは意識の低さが大事だと思っていて、低きに流れた先が最短ルートで目的というのが大事なんじゃないかと。何かを探すときはまずスタートボタン（Windows95）。困ったらホームボタン（iOS）。OSごとのUIガイドラインに従うのも、そのユーザーにとってすでに常識となっている使い方に対応することで、ユーザーに新しい学習を強いることなく使えるようにしてあげると。意識低い重要。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">printデバッグは初心者がとっつきやすいけど効率が必ずしも良くない方法の代名詞みたいになっているけど、printを置いたところが勝手にブレークポイントになって、そこのスタックが取れたり変数が取れたり、変更検知とか、すごいprintデバッグに進化してもいいのになってたまに思う。</p>&mdash; 渋川よしき (@shibu_jp) <a href="https://twitter.com/shibu_jp/status/867921375108800513">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

で、こういうことをツイートしたわけです。

いろいろ反応があったので、まとめておきます。

<blockquote class="twitter-tweet" data-conversation="none" data-lang="en"><p lang="ja" dir="ltr"><a href="https://twitter.com/shibu_jp">@shibu_jp</a> print文の出力結果が全部クリッカブルで、クリックするとその出力時点のスタックフレームに入って対話的実行できる時代が来るよ！</p>&mdash; nishio hirokazu (@nishio) <a href="https://twitter.com/nishio/status/867957982495100930">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

いまのところ雑なprintデバッグでこれに近いのはChrome/SafariのDevTool。出力すると、出力した場所の情報も出てきます。オブジェクトとか配列は構造化されていてクリックして中を覗いたりできます。もう１つ思い出したのはWerkzeugのデバッグ機能ですね。ウェブサーバー内でエラーが発生すると、スタックトレースがブラウザ上に表示されて、それぞれのスタックの中の変数とかを覗いたり、それぞれのスタックの名前空間でスクリプトを実行できるやつ。

http://hikozaemonchan.blogspot.jp/2010/12/werkzeug.html

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">汎用機な時代には、オペレータリプライ要求付きのコンソール出力命令がカーネルサービスにあってだな、、、けっこうデバッガ的に使ってたヤツもいたような <a href="https://t.co/RCNvWwPrm1">https://t.co/RCNvWwPrm1</a></p>&mdash; みんつ＠よこはまちほー (@migimatsu) <a href="https://twitter.com/migimatsu/status/867980049583972352">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">rubyのpryのことかなぁ <a href="https://t.co/RovUcG73zM">https://t.co/RovUcG73zM</a></p>&mdash; M.Futakawa (@fm_fata_morgana) <a href="https://twitter.com/fm_fata_morgana/status/867992094010245121">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">そういや、JSにはdebugger statementがあったな <a href="https://t.co/3VrozYou6z">https://t.co/3VrozYou6z</a></p>&mdash; Wreulicke:?人 (@wreulicke) <a href="https://twitter.com/wreulicke/status/868141338402766849">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">PowerShellなら環境変数の$DebugPreferenceとWrite-Debugコマンドレットで、デバッグストリームにメッセージ出しつつブレークしたり継続確認のプロンプト出したり <a href="https://t.co/SbBLrhBpFq">https://t.co/SbBLrhBpFq</a></p>&mdash; KIMATA RobertHisasi (@robert_KIMATA) <a href="https://twitter.com/robert_KIMATA/status/868001858303926276">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

http://qiita.com/k0kubun/items/b118e9ccaef8707c4d9f

なるほど、binding.pryやJSのdebuggerステートメントとデバッグ出力を兼ねると僕が妄想してたやつに近そうです。リプライ要求付きコンソール出力命令というのはいいですね。

<blockquote class="twitter-tweet" data-conversation="none" data-lang="en"><p lang="ja" dir="ltr"><a href="https://twitter.com/shibu_jp">@shibu_jp</a> 昔作ったおもちゃ言語で、「メモリダンプを吐き出す命令」をソース上のほぼ任意の位置に書ける文法にしときました。</p>&mdash; 非実在naka aki (@naka_aki_spl) <a href="https://twitter.com/naka_aki_spl/status/868104634706968581">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="en"><p lang="da" dir="ltr">trace_printk() <a href="https://t.co/uy0DiXe6pU">https://t.co/uy0DiXe6pU</a></p>&mdash; まさみさんは語りたい (@mhiramat) <a href="https://twitter.com/mhiramat/status/867926164148412417">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

そうですね。出力する情報を増やすというのは手っ取り早く効率があがりそうです。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">主に組み込み向けですが、自動で関数の開始終了分岐にprint文的なものを挿入。そのままコンパイルして動作させてログを収集、処理の流れや関数の呼ばれた回数、処理時間などを見える化できるツールがあって便利に使ってました。DT10とか。変数も出せたと思う。 <a href="https://t.co/hpJUCVL50b">https://t.co/hpJUCVL50b</a></p>&mdash; Tomoya Miwa (@tomoya0x00) <a href="https://twitter.com/tomoya0x00/status/867927781518135298">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

C言語とかだとマクロでいろいろやったりはありますよね。そういえばバグベアードというのもありました。

https://www.slideshare.net/wraith13/ss-7982683

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">わかる。optimized out防止に調度良い。<br><br>が、それ故に「debug printをこういう風に入れた場合だけ何故か動く」系に弱く、やっぱり良し悪しだよなー、となる <a href="https://t.co/dBN3H3Mgax">https://t.co/dBN3H3Mgax</a></p>&mdash; ichimal (@ichimal) <a href="https://twitter.com/ichimal/status/867982999517708289">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">ハサミと一緒で使いよう プリントデバックはシーケンス処理のデバックには向いてるので多用するのが正解 落ちる系やキワなタイミング依存系やメモリ破壊系やらのデバックに使ったら時間がかかるだけで得られるものは少ない <a href="https://t.co/IexrIMQ9W0">https://t.co/IexrIMQ9W0</a></p>&mdash; へちょ顔ヤマヒデ@横浜 (@hidekunyamamoto) <a href="https://twitter.com/hidekunyamamoto/status/868241308061585408">May 26, 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

このあたりは別の手法が必要ですね。Goだと、静的チェックではなくて動的にクリティカルセクションを探し出すraceチェック機能がありますしね。

妄想をアウトプットするといろいろ反応があって楽しいですね。