【RubyKaigi発表予告】error_highlight: user-friendly error diagnostics

技術部の遠藤です。2日連続の投稿です。

今年のRubyKaigi 2022ではTRICKの発表をしますが、もうひとつ真面目な発表もします。Ruby 3.1の目玉機能であったerror_highlightについてです。

この発表内容について、あらすじを紹介したいと思います。

Ruby 3.1のerror_highlightとは

Ruby 3.1でNoMethodErrorが発生すると、次のようなエラーが表示されます。

$ ruby test.rb
test.rb:1:in `<main>': undefined method `time' for 42:Integer (NoMethodError)

42.time { print "Hello" }
  ^^^^^
Did you mean?  times

この42.time { print "Hello" }とその下線を出しているのがerror_highlightという機能です。

当日は実装をかんたんに発表しますが、この内容はすでに記事を書いているので、興味があれば読んでください。

techlife.cookpad.com

Ruby 3.2で何が変わるか

ざっくり言えば2つです。

  • ArgumentErrorやTypeErrorでも下線が出るようになる
$ ruby test.rb
test.rb:1:in `+': nil can't be coerced into Integer (TypeError)

1 + nil
    ^^^
  • Railsのエラーページでも下線が出るようになる

Railsのエラー画面のerror_highlight

これだけなんですが、これらを実現するためにRubyインタプリタのエラー処理まわりをいろいろと整理する必要がありました。

何がむずかしかったか

一言で言えば、「エラーメッセージの変更は非互換である」ということでした。

Ruby 3.1のerror_messageはException#messageをオーバーロードしてerror_highlightのメッセージを出すので、要するにエラーメッセージを書き換えていました。しかしエラーメッセージはターミナルなどに表示されるだけではなく、テストで参照されたり、ログファイルに書かれたりもするので、むやみに変えると非互換が問題になるのでした。

Ruby 3.1では比較的影響の少なそうなNameError/NoMethodErrorにとどめたのですが、それでもいくつか困りごとが報告されていました。いきなりArgumentErrorやTypeErrorに対象を広げると更に大きな問題になるので、非互換問題を先に解決する必要がありました。

Ruby 3.2の新機能、Exception#detailed_message

どうすればよいか。本来のException#messageを書き換えることなく、ターミナルなどに表示するメッセージだけ書き換えればよいです。

そこで、Exception#detailed_messageという新規メソッドをRuby 3.2に導入しました。

#message は従来どおりのシンプルなメッセージを返します。

puts $!.message
#=> undefined method `time' for 1:Integer

#detailed_messageはerror_highlightやdid_you_meanの情報が付加されたメッセージを返します。#detailed_messageは内部的に#messageを呼んでます。

puts $!.detailed_message
#=> undefined method `time' for 1:Integer (NoMethodError)
#
#     1.time
#      ^^^^^
#   Did you mean?  times

テストやログでは従来どおり#messageを使い、ユーザにエラーを表示したいときは#detailed_messageを使う、という風に使い分けることになります。Rubyインタプリタのエラー表示も#detailed_messageを使うようにしました。

これで、#messageの内容を変えずにエラー表示を拡充出来るようになったので、非互換の問題なくArgumentErrorやTypeErrorでも下線を表示できるようになりました。

エコシステムへの対応

この#detailed_messageの変更は、Rubyのエラーを表示するフレームワークにちょっと対応をしてもらう必要があります。たとえばRackの開発モードのエラー画面では、did_you_meanやerror_highlightの情報も出してほしいでしょう。そのためには、#messageではなく#detailed_messageを使うようにする必要があります。

Rackについてはプルリクエストを送ってマージしてもらいました。シンプルなので参考になると思います。

github.com

Railsについては、単純に#detailed_messageを使うのではなく、error_highlightのAPIを直接使って専用の表示をするようにしました。

github.com

SentryとDataDogは、Exception#detailed_messageを提案したチケットの中で、#detailed_messageを使うようにすることを約束してくれました。彼らの同意が得られたから#detailed_messageが導入できたという背景もあります。

しかし、エラー表示をしたいフレームワークは他にもたくさんあるので、地道に対応していく必要があるでしょう

まとめ

Ruby 3.2のerror_highlightでは、

  • ArgumentErrorやTypeErrorでも下線が出るようになります。
  • Railsのエラーページでも下線が出るようにもなります。

この2点を実現するために、Rubyのエラー処理まわりを整理しました。

という話を、RubyKaigiでします *1 。3日目の一番最初のトークです。興味あればぜひ。

また、お使いのフレームワークに#detailed_messageを対応させる必要があるのかもしれません。Ruby 3.2にしたときに「did_you_meanやerror_highlightが表示されてないな」と思ったら、この内容を思い出してフレームワークにプルリクを作るなどしてもらえるとうれしいです。

*1:記事では省略しましたが、インタプリタが余計なことをするせいで下線位置がずれてしまう!というバグ修正の話なども。

【RubyKaigi発表予告】超絶技巧コードコンテストTRICK 2022結果発表

技術部の遠藤です。CookpadのフルタイムRubyコミッタの1人です。RubyKaigiまであと1週間ですね!

今年のRubyKaigiでは、"TRICK"の発表をします。TRICKとは何か。まずはこのRubyコードを見てください。

->\
&\
w{
a=
?a
b=
?b
c=
?,
d=
?.
e=
?e
g=
?g
h=
?/
i=
?{
l=
?l
m=
?_
n=
?$
o=
?1
q=
?'
r=
?<
s=
?s
t=
?>
u=
?u
v=
?v
x=
?(
y=
?)
z=
?-
_=
""
f=
w[
w,
z+
t+
i+
m+
r+
r+
m+
o+
d+
g+
s+
u+
b+
x+
n+
h+
c+
q+
q+
y+
?}
];
f[
'p
ut
s"
He
ll
o,
']
_\
<<
32
f[
'w
or
ld
!"
']
w[
w,
e+
v+
a+
l+
x+
m+
y]
}[
&[
*(
:\
a\
..
:\
ÀÀ
)%
(0
3\
**
7*
47
;)
][
+1
]]

もう一度いいますが、これは「Rubyコード」です。保存して実行すると、"Hello, world!"と出ます。

$ ruby hello.rb
Hello, world!

TRICKとは、こういう変なRubyコードで競い合うプログラミングコンテストです *1 。読めないけれど面白い投稿作品(プログラム)が選定され、表彰されます。

TRICKは2013年、2015年、2018年とやってきて、今回は4年ぶり4回目の開催になりますが、いままでで一番レベルの高い戦いになったと思います。というのも、上のプログラムは、TRICK 2022に落選したプログラムです。*2

つまり、当日はこれよりすごい入賞作品たちが紹介されます。TRICK 2022 Resultsは1日目の夕方です。ご期待ください!

rubykaigi.org

おまけ

開発者ブログなので、上記のプログラムの技術解説を軽く書いておきます。

基本構造はこうなってます。

-> &b { b["dummy", "<main code>"] }[&:eval]

ラムダ式に:evalをブロックとして渡すことで、:evalが暗黙的にto_procでProcに変換されます。そのProcに"<main code>"が渡されることで、Kernel#evalが呼び出されて、最終的にmain codeが実行されます。

<main code>のところは、↓のような感じで縦長にしています。

a = ?p
b = ?u
c = ?t
d = ?s
a +
b +
c +
d   #=> "puts"

一番むずかしかったのが:evalというシンボルを作り出すところです。あっさりネタをばらすと、:aから始まるシンボルのRangeを列挙すると、102,789番目が:evalです。

(:a..:ÀÀ).to_a[102789] #=> :eval

:ÀÀというUnicodeなシンボルを使うところが肝。2文字分でありながら4バイト超なので、列挙が途中で打ち切られずに:aから:zzzzまでの配列が得られます。

あとは読み解いてみてください。

なお、実際に投稿したのはHello, world!ではなく、任意のRubyコードを縦長に変換するコードでした。完全な投稿は↓に置いたので興味あればどうぞ。

github.com

おまけのおまけ

ぜんぜん別の宣伝ですが、RubyKaigi当日はぜひ会場内のクックパッドブースに来てみてください! 今年もなんか企画が用意されているはず。

*1:Transcendental Ruby Imbroglio Contest for rubyKaigi の略ですが、この正式名称は遠藤も覚えてないです。

*2:投稿者には採否の連絡をしていないのですが、これは遠藤自身が投稿して落選したコードなので、特別に先出ししています。

技術選定で失敗しない、正解にする力

プログラミングが好きなエンジニアの渡辺です。

先日 TechMTG という社内のエンジニアミーティングの場でお話させて頂いたことを書いてみようと思います。 表題の「正解にする力」というのは様々な意思決定に適用出来るものとして考えていますが、今回は技術選定という観点でお話します。

技術選定というと、世の中のデファクトだとか、新しい技術だとか、社内で実績のある枯れた技術とか色々な理由や基準で選ぶのが良いと、至るところで言われていると思います。 選定時に議論が平行線にならないように、判断基準を設けるべきというのもあるでしょう。 これらは重要であり、検討、準備することは必要ですが、それに加えて「正解にする力」というのも重要なのではないか?という提案です。

まず、組織における技術選定とは「正解を選ぶ」ことではないと思っています。 これはその技術選定結果はその人個人についてまわるのではなく、組織として維持し続けなければならないからです。 また、選定した人だけでなく、組織の他の人も同じように技術を活用している状態を作ることも必要です。 採用理由がいかに合理的であろうが、判断基準を満たしていようが、世の中のデファクトだろうが、賛同者がいなければ独りよがりになってしまいます。 なので重要なのはその選択を「正解にする力」なのです。 もちろん選択も「正解にしやすい」「正解にし続ける」ためにより確度が高い選択はあると思っています。 それは前に述べた、採用理由や基準というものです。 「正解にする力」とは分解すると「正解にしやすくする」と「正解にし続ける」となります。

「正解にしやすさ」とは

「正解にしやすさ」は賛同してもらいやすさとも言えます。 これは世の中のデファクトだったり、流行りだったり、社内実績がすでにあったりと賛同してもらうための条件がすでに整っている場合です。 もしくは提案者の技術的信頼があり、人に賛同して貰うという場合もあるでしょう。 勉強会などの啓蒙活動や実績を作って行くという行動がこれにあたります。

「正解にし続ける」ということ

「正解にし続ける」は組織や、仕組みとして成り立たせることとなります。 技術に完璧な銀の弾丸はありません。 見方を変えればみればどんな技術にもデメリットになるポイントもあるでしょう。 それを踏まえて総合的にメリットが多く、リスクが低いことがある意味技術選定の「正解」と言えるでしょう。 それは総合的なメリットやリスクを抑えるために、前提としている事柄を維持しないと「正解」ではなくなってしまいます。 これを維持するために組織の役割に組み込んだり、仕組み化をすることが「正解にし続ける」ことです。 例えば AWS を使っていなかった組織が AWS を使うようにしたとして、最初の導入は有識者が行ったとしても、それをサービスチームに移管した後、受け入れられる状態にしなければいけません。 サービスチーム側の組織に責任を持つ役割を作ったり、または基盤側の組織としてサポート体制を作ったり、権限管理やコスト管理を効率的に行えるようにしないと属人化したり、評価として行えない状態になってしまいます。 また、デメリットの理解を組織の共通認識にし、それに対する対応方法まで整備することも重要です。 そうしないと後述する技術負債を生むことにもなりかねません。

一人で「正解」にする必要は無い

大きな影響を与える判断を一人で「正解にする、し続ける」ことが難しい場合は協力が必要となります。 その協力を得られるかどうかも、その人の「正解にする力」の一部です。 協力を得るのはチームだけでなく、会社として、ひいては世の中全体までいけば最高ですね。 (今はデファクトでなくても自身がオープンソースなり設計思想なりで広めてしまえばいいということです)

正解を「選ぶ」人

「正解を選ぶ」だけの人はその判断理由や基準に対して正解ではなくなってきた時に何もすることができません。 これは正解とするための前提として置いた事柄が変わった場合の話ですね。 「前はそれで正しかったけど、今はこっちが正しい」となるだけとなってしまいます。 もしくは前提が変わったのに「この技術課題にはこの技術が正しい」と言い続けるだけです。 こういった人の技術選定は最初は採用されても採用され続けるのは難しいと思っています。 なぜなら、技術選定は一回判断すると切り替えるのが難しくコロコロ変わるとついていけないからです。 もちろん、世の中的なデファクトが長く続く技術を選べば「正解を選ぶ」だけでも結果的に正解になることもあります。 私としてはこの「選ぶ」と「正解にする」の違いを理解しているかどうかが、技術選定を任せられるかどうかの判断基準となっています。

今の技術に固執することではない

誤解してほしくないのが、本記事で書いている「正解にする力」は「特定の技術を何が何でも維持する」ということではありません。 変化を起こした方がいいことも、もちろんあります。 なので変化していくための技術革新を「正解」にすることも含んでいます。 そのときに、「今のやつをリファクタリングする時間を使ってでも、こっちにしよう」と働きかけたり、そのための理解を得るようにすることが「正解にする力」です。 理解を得るために、今まで前提としていた事柄を変えにいったり、変えたことによるメリットを最大化するために活動することでもあります。

選定基準

技術選定の基準に関しては本記事の範囲外ですがひとつだけ。 「正解を選ぶ」人はその「技術としての正しさ」を最重要視し、それ以外の事柄をそれに比べて軽視する傾向があると思っています。 「技術としての正しさ」は選定基準の前提であり、それが間違っている技術は候補に上がらないだけです。 技術的正しさというものに尺度があるとして、より技術的に正しいものを選定するのではなく、その候補から自身の組織に対してどれが一番メリットが大きく、リスクが低いかということでしょうか。 このあたりの話は他にもいろいろな技術選定基準や理由を書いてくれている記事はたくさんあると思います。

技術負債

技術負債という言葉には色々な意味があると思いますが、今回の話の文脈でということでお話します。 誰しもが見て「これは技術負債だ」と決まっているものはありません。 ただ、大多数が「これは技術負債だよね」となることはありますよね。 これは、「正解にする力」の「正解にし続ける力」がなかったことも要因の一つではないかと考えています。 技術に対する理解が全員に行き届かず、誤った使い方が蔓延してしまった その技術のデメリットを最小化することを怠った これらを維持するための仕組みがそもそもなかった きっちりその技術に対して、組織で、仕組みで正解にし続けることが出来れば大多数が「これは技術負債だよね」とはならないのでは無いかと思っています。 そしてデメリットの部分は承知の上なので、そこを見て「技術負債だよね」という人も減るでしょう。 そしてそれはその技術を選び続けることが一番のメリットであることを会社的にも証明、維持することと同義です。 そして変化に対応する必要になった場合は、「正解する力」によって変化していくことが出来るので、結果的に技術負債を抱えている期間が短くなるのではと思っています。

「正解にする力」を持っている人

ざっくばらんに言えば、この「正解にする力」を持っている人がテックリードであったり技術選定を任せられる人なのかなと思っています。 技術選定には対象の技術を正しく理解する力はもちろん必要ですが、それをいかに組織の「正解」とするかも同じぐらい重要だと思います。 そして単に、開発のことだけでなく採用や評価制度、育成に対してのメリットを最大化していく意識も必要です。

最後に

この「正解にする力」は技術選定だけではありません。 サービス、機能、組織、評価や評価制度等なんでも自らの「意思決定」に対して当てはまります。 それぞれの意思決定で「課題への正しい理解」「当事者意識」「巻き込み力」「やり抜く力」等をある意味一言で表した言葉です。 これは瞬間的な正解、不正解ではなく、再現性がある継続的な力です。

「正解にする力」という言い回しは、数学のように「正解とはすでに決まっていて、それを見つけるもの」というバイアスがかかっている「正解」に対して、それを自らの力で「正解にしてしまう」という表現にすることで簡潔に私の意図を伝えやすいかなと思ってこの言葉にしています。

いろいろ書きましたが皆様の人生で何かの参考になれば幸いです。 皆様の中での理想の技術選定を歩んでいってください。

クックパッドたんによる正解にする力の要約
クックパッドたんによる正解にする力の要約

要約の画像は知り合いに書いて頂いたものを使わせて頂いています。
また、キャラクターについては©ナイセン様のクックパッドたんを使わせて頂いています。

twitter.com