今年はソフトウェアのデバッグ手法の一つ、ラバーダック・デバッグについて自分なりの考えを広げられた一年でした。本来の手法とは異なってる可能性がありますが、ひとつの考え方として見てもらえれば幸いです。
ラバーダック・デバッグ?
ラバーダック・デバッグ とは、ソフトウエア工学におけるコードのデバッグ手法である。ラバーダック・デバッグは、The Pragmatic Programmer[1]という本で紹介された、プログラマーがラバーダックを持ち歩きアヒルちゃんに向かってコードを1行ずつ説明することによりデバッグを行うという話が由来である。この手法には、他にも多くの別名があり、しばしば様々な無生物が用いられている。
私はこの手法を、自分の考えを整理することに使えるデバッグ手法、と捉えています。でも実際におもちゃに向かってブツブツと話す行為は確実に迷惑です。ではどうやってラバーダック・デバッグをすればいいでしょうか?
より現実的なラバーダック・デバッグ
ラバーダックの代わりとなる道具をいくつか紹介します。
Slack
いつのまにか随分と使われてますね。特に分報という運用ルールとラバーダック・デバッグの相性は良いです。ほぼ自分しか書き込まない場所をラバーダックと捉えて、考えやコードの断片などを書き殴ります。
ある程度は時と状況などを弁える必要はありますが、声に出して話しかけるのと違って読み返すことができます。タイミングが良ければ他の人からレスポンスがもらえるかもしれません。
IRC みたいですね。
メリット: お手軽
デメリット: ある程度パブリックに向けて発信しているということを意識する
デバッグ効率: ★★☆
植物
全然関係ないことをしてるときにふと妙案が浮かぶ、そんな経験を誰しもしているのではないでしょうか。思考する環境をちょっと変えたいときに便利なのが植物です。観葉植物のお世話をしながら物を考えるのは、なかなかにいい体験です。和みます。今ではこのモンステラは私にとって相棒のようなものです。
メリット: 植物に気が向くようになる
デメリット: 植物を用意する(植物を貰うことありますよね?)
デバッグ効率: ★☆☆(慣れるとただの風景になる)
普段とは違う場所で作業する
ラバーダックどころの話ではないですが、思考中のことをステークホルダに話してみたい、でもそういう人が自分の近くに来ることはあまりない、ということはないでしょうか。
この問題に対して辿り付いた手段がスタンディングワークです。上記の手段と違い、環境整備が難しいですが私にとって一番効果が高いです。呼び止めたい人が視界に入ったらすぐにでも会話を始められます。
かれこれ1年間継続しているんですが、私の性格には意外と合ってるようです。
メリット: 目立つ、体力を使う
デメリット: 目立つ、体力を使う
デバッグ効率: ★★★
まとめ
このように見方を変えればラバーダック・デバッグの応用方法が見つかるものです。来年もまた色々な手段を探していきます。
おまけ
ラバーダックの話だけだとアレなのでイチオシのツールを一つ紹介します。
Amazon Athena
動作明快。処理が早い。ただ JSON 関数の挙動が Presto と違うっぽい。例えばあるカラムに JSON が入ってて集計したい。jq だとこんな感じ。
$ echo '[{"name": "item1", "count": 1}, {"name": "item2", "count": 2}]' | jq '[.[] | .count] | add'
3
まず Athena で各オブジェクトを扱うためにキャストが必要そうで ROW が使えそう、のはずなんだけど Presto のサンプルのクエリが通らない…
6.12. JSON Functions and Operators — Presto 0.229 Documentation
--- Error running query: SYNTAX_ERROR: line 1:170: Cannot cast json to row(v1 bigint,v2 varchar,v3 boolean)
SELECT CAST(JSON '{"v1":123,"v2":"abc","v3":true}' AS ROW(v1 BIGINT, v2 VARCHAR, v3 BOOLEAN));
これは Athena が使っている Presto のバージョンが古いせいらしい。
Cast json object to row not working · Issue #12949 · prestodb/presto
そこでバッドノウハウを考えた。map で値を varchar にキャストしてから integer にキャストし直すとアラ不思議。意図通り集計できる。
お試しあれ。
select sum(reduce(
cast(JSON '[{"name": "item1", "count": 1}, {"name": "item2", "count": 2}]' as array<map(varchar, varchar)>),
0, (s, x) -> s + cast(x['count'] as integer), s -> s))
;
-- 3