カレーの恩返し

おいしいのでオススメ。

Ruby の静的型チェック × ISUCON という夢

RubyKaigi 2024 お疲れさまでした。楽しかったですね。

みなさん RubyKaigi で持ち帰ったものは色々あるんじゃないかと思いますが、自分が持ち帰ったものは Ruby の静的型チェック × ISUCON でした、という話を書こうと思います。ポエムです。

ISUCON の説明はこの記事では割愛します。ISUCON のサイトに書いてある説明の引用だけ貼っておきます。

ISUCONとはLINEヤフー株式会社が運営窓口となって開催している、お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトルです

https://isucon.net/

 

突然ですが、最新の ISUCON である ISUCON13 の利用言語比率は以下のようになっています。

ISUCON13 利用言語比率

利用率の全体ランキングは以下の通りです

Go   465組 70.8%

Ruby   61組   9.3%

Nodejs 47組   7.2%

Python 34組   5.2%

Rust  25組   3.8%

PHP  19組   2.9%

Perl     5組   0.8%

Bun     1組   0.2%

 

上位30チームに限定すると以下となりました

Go   29組 96.7%

Ruby   1組   3.3%

 

https://isucon.net/archives/57995340.html

Go の利用比率が 70% を超えてますね。すごい。近年の ISUCON は Go の一強と言えそうです。
それでは、自分が初めて参加した ISUCON である ISUCON7 の予選の利用言語比率を見てみましょう。

オンライン予選 利用言語比率

利用率の全体ランキングは以下の通りです。利用言語は自由記入で複数入力したチームもありますので合計が回答チーム数を超えます。

Ruby  68組 31.2%

Go   62組 28.4%

Python 28組 12.8%

PHP  25組 11.5%

Perl   19組 8.7%

Node.js 18組 8.3%

C#    1組 0.5%

 

本選出場が決まった30チームに限定すると以下となります。

Go   16組 53.3%

Ruby   6組 20.0%

Node.js  4組 16.7%

Python  2組 6.7%

未回答   1組 3.3%

 

https://isucon.net/archives/51000131.html

なんと、Go よりも Ruby の方が利用比率が高くなっています。というよりも、満遍なく色々な言語が使われていますね。

この数年間でここまで取り巻く環境が変わったのは一体なぜなんでしょうか。これは Ruby から Go に乗り換えた人に話を聞いてみるしかありません。

…はい、私です。ISUCON7は Ruby で参加していましたが、ISUCON13 は Go で参加しました。
普段業務で使うのは Ruby ばかりだし、こういうときくらい他の言語でもかじっておくかという気持ちは多少あったりしますが、本当に勝ちたいと思ったときにどっちを使うかと問われたとしても結構悩みます。Ruby はずっと使い続けていて Go は業務ではほとんど使ったことがないにしても、です。


どうしてそう思うのでしょうか。
まず頭に思い浮かんだのは言語のパフォーマンスです。Ruby よりも Go の方が速そうです。
ただ、RubyKaigi でも話があったように Ruby は十分速い言語になっています。優勝争いをするのなら少しのパフォーマンスも気にするかもしれませんが、自分が ISUCON に参加するときはそのレベルまでチューニングができた試しがありません。また、例年 Ruby で参加している白金動物園は上位争いにおいても Ruby で戦えることを証明しています。

パフォーマンス面においては Ruby も十分速いことを理解しました。では次回の ISUCON は Ruby で参加しようと思え……ませんでした。
というのも、個人的には最も大きな要因は「ISUCONにおける開発生産性の差」にあるのではないかと考えています。

 

ISUCON は普段開発を行う環境とは異なる特殊な環境です。具体的には以下が特殊だと考えます。

時間制限がシビア

ISUCON は8時間という限られた時間の中で対処を行う必要があります。そのため、普段の業務では行わない判断も時には正しい判断となることがあります。

テストがない

普段業務で開発を行う際はテストがあるのが当たり前です。テストコードなしで本番にデプロイするのは怖くてできません。しかし、ISUCON はテストがない状態からスタートします。業務なら「テストがないならテストを書けばいいじゃない」とテストを書くかと思いますが、ISUCONにそんな時間はありません(少なくとも自分はそう捉えてしまっています)。

なので、ベンチマークをテスト代わりに使います。そのために、コード修正のフィードバックサイクルが数分かかることはザラです。ベンチが詰まっているときは10分くらいかかることもあります。

普段の仕事であまり使わないライブラリを使う

普段業務で使うライブラリはだいたいのクラスやメソッドが頭の中に入っています。そのため、ドキュメントをあまり読まなくても一筆書きである程度の確率で動くコードを書くことができます。しかし、ISUCON では普段使わないライブラリを使うことが求められます。業務では ActiveRecord を使う DB 操作が ISUCON では Mysql2 を使って操作を行う必要があります。

そのため、それらのメソッドを正しく使うにはドキュメントを読まないといけません。きちんとドキュメントを読みに行くのならいいのですが、ISUCONは時間制限がシビアなので「こんな感じで動くのでは?」とそれっぽい実装をしてみてテスト代わりのベンチマークを実行します。だいたい一筆書きでは動きません。ちょっと修正してベンチマークを実行して、ちょっと修正してベンチマークを実行して… と一回のコード修正のフィードバックサイクルが遅いのにも関わらず何度も実行する羽目になり時間を浪費してしまいます。

(このあたりは猛者は過去問を何度も何度も練習することにより、ISUCON 頻出ライブラリを頭に叩き込んでいるんだと予想しています。ただ、自分は ISUCON 本番までに 2,3回程度しか練習しないことが多いのでなかなか覚えるまでに至っていないことが多いです…)

 

要するに、コード修正のフィードバックサイクルが遅いのと、ライブラリの使い方を頭に叩き込んでいないといけないのが問題なわけです。

対して Go はどうでしょうか。Go もテストはないのでベンチマークを実行しないと正しく動くかは保証されませんが、Linter やコンパイルによって実行前に型チェックでコケる部分を教えてくれます。また、エディタのサポートによって関数にどんな引数を渡したらどんな返り値が返ってくるのかを教えてくれます。このときのコード修正に対するフィードバックサイクルは1秒かからないくらいなのではないでしょうか。

また、ベンチマークの結果が教えてくれるのは「このエンドポイント叩いたら500になったよ」という結果だけです。ベンチマークが失敗したら自分でシステムログを見に行ってどんなエラーが発生したのかをログの中から見つけ出す必要があります。


…と前振りがかなり長くなってしまいましたが、自分は ISUCON で Ruby でもパチパチっと型がハマった開発ができると開発体験が一変するのでは?と感じました。

上記の Go のような体験は gem_rbs_collection, rbs-inline, typeprof 周りが整ってくれば実現できると思います。そうなれば、自分があまり慣れていない Go を使うよりも Ruby を使った方が ISUCON で勝ちやすくなりそうです。

もちろん、Ruby の参考実装には十中八九型はついていないので ISUCON 競技開始の最初の 10~20分を使って rbs-inline でアプリケーションの型を書くのはオーバーヘッドとして必要です。ただ、コードの全体像を把握するのにも価値がある時間の使い方だと思いますし、全然許容範囲内です。

現状では、おそらく ISUCON の Ruby の型周りを整備しようと思った人はあまりいないと思うので型付けを10~20分で済ませるには色々やる必要があるはずです。

  • ISUCON 頻出のライブラリの型を書く
  • ISUCON で使う上での rbs-inline, steep, typeprof の足りない機能のフィードバック、patch を送る
  • 型のためのコード量を減らすような gem を作る(?)

自分ができることを探して、自分が ISUCON で勝つために Ruby を使いたいと思える世界に近づけるようやっていきたいと思います。整備が終わるまで kaigieffect 続いてくれ…!