RubyKaigi 2024 で学んだこと・社員として参加する理由
こんにちは。わこーです。沖縄から帰ってきた日は顔がヒリヒリしていました。日焼けすごい。
この記事では主に RubyKaigi 2024 に参加し、主に ruby.wasm を中心に学んだことや思ったことを書いていきます。
なぜ ruby.wasm かというと、私は Ruby のコードが様々な環境で動くことに興味があり、今回聞いたセッションはその視点で選んでいたからです。
余談ですが、どこでも動く言語がほしいならGoでいいじゃんと以前友人に言われましたが、私はRubyで書けるという点に魅力を感じています。
Ruby を1つのバイナリにパッケージングする
※これは ruby.wasm の話ではないです
まず最初に紹介したいのが、ahogappa0613 さんの発表、It's about time to pack Ruby and Ruby scripts in one binaryです。
ahogappa0613/kompoというツールの発表が印象的でした。これは Ruby で書いたスクリプトを1つのバイナリとしてパッケージできるツールです。
このツールを開発するモチベーションとして、環境差異の吸収が挙げられています。
インストールされている Ruby のバージョン違いや、gem のバージョン違いなどが原因で動かないことがあるため、 バイナリにして配布することで環境差異を吸収できるというのは魅力的です。
過去にも同様の課題の解決を目的としたツールはありましたが、Ruby 3.0以降に対応していなかったり、一時ファイルを作成する必要があるところに課題を感じていたそうです。別の言語だとPythonではPyInstallerがよく使われています。PyInstallerも同様の問題がありそうです。
一時ファイルの作成が必要だった点に関しては kompo では新しくvfsを用意することで解決しているようです。この手法が一般的なのかはわかりませんが、仮想環境のためにvfsを用意した点でなんとなくruby.wasmも似たアプローチをしていたなというのを思い出しました。
どこでも動くツールが簡単に作れることは魅力的で、そのために私はRustを使うことがあります。 Rubyを使う理由と同じで、書き心地がいいのと、どこでも動かしやすく、早いのが魅力に感じています。
Matzさんもキーノートでシングルバイナリに出来るといいな、AOT Compiler があるといいのかなと話していました。調べてみると、PythonのNukitaがそういったことをしているように見え、先行事例にあたりそうです。
kompo は AOT Compiler を備えていませんが、実際に動くものが出来るので、その体験の価値検証になりそうです。
ruby.wasm のブラウザ上での非同期処理
次に、廊下でruby.wasmのメンテナーの kateinoigakukun さんにした質問の共有です。
ブラウザでruby.wasmを使い、DOMのClickイベントのコールバック内で非同期処理をする場合はFiberを使う必要があります。
これは公式ドキュメントに記述がなく、正しい書き方なのかどうかわからないという疑問を持っていました。
たとえば、example.com
からデータを取得して、コンソールに書き出すという処理を考えます。
ドキュメントを読む限り、以下のようなコードを書くと思います。
require 'js'
def something_async_method
url = 'http://example.com'
JS.global.fetch(url).await.json.to_s
end
button = document.getElementById('button')
button.addEventListener 'click' do
result = something_async_method.await
puts result
end
しかし、このコードは動きません。以下のエラーが出ます。
Uncaught Error: /bundle/gems/js-2.5.0/lib/js.rb:86:in `await': JS::Object#await can be called only from RubyVM#evalAsync or RbValue#callAsync JS API
期待した結果を得るには、リスナーを次のように書く必要があります。
button.addEventListener 'click' do
Fiber.new {
result = something_async_method
puts result
}.transfer
end
なんとなく場当たり的な書き方に感じていたので、この書き方が正しいのかどうかを質問しました。
これに関しては「よく気づきましたね」と驚かれ(←うれしい)、まさにイベントリスナー内でFiberを使う必要があるという回答でした。
イベントリスナー内でFiberを利用する必要があるかどうかをメソッドの利用者が判別して書き分けるのは、呼び出すメソッドの内部について知っている必要があります。
それは使い勝手がよくないと感じたので、 イベントリスナー内で常に Fiber.new { ... }.transfer
を勝手に内側で生成するのはどうかという提案をしました。
しかし、レンダリング回数に応じてFiberが生成されるため、メモリリークの可能性があり、それは悪手だと思うという回答でした。(私もそう思います)
他に、js
gem内で def async(&block) = Fiber.new(&block).transfer
というメソッドを定義しておき、次のように書けるといいのかなという提案もしてみました。
button.addEventListener 'click' do
async { something_async_method }
end
それなら次のような書き方も考えられるという提案がありました。
button.addEventListener 'click', js.async do
something_async_method
end
これは確かに、JavaScriptの書き方に似ていてフロントエンドという領域では、わかりやすいです。
button.addEventListener('click', async () => {
await something_async_method();
});
ただ、いずれにせよ something_async_method
が非同期実行であることを呼び出し側が知る方法がないので、良い方法を考えたいです。
また、ledsun さんの発表、 Using Ruby in the browser is wonderfulでは、 require_relative
が使えるようにしたという話もありました。
フロントエンドで ruby.wasm を動かすという土壌が少しずつ整っているように感じられます。
今後はwebpackのようなものが出てきたり、Tree shakingできるようになったりするのでしょうか。必要なgemを全部同梱して配信って重いですしね。
async/await について
RubyKaigiの少し前にXではこのなポストが話題になっていました。
RubyKaigiではMatzさんからも async/await についての言及がありました。
Rubyで実装されるとしたら、どんな感じになるのでしょうか。
現状、以下のような書き方があります。配列に対して map
を使うときに lazy
を使うことで、遅延評価を行うことができます。
[1, 2, 3].map { |i| i.to_s }.lazy
遅延評価が必要な処理を書いた時に、先に lazy と書かないような Ruby での書き方を考えると、以下のような書き方になるのでしょうか。
result_a = fetch(url).async
result_b = fetch(url).async
[result_a, result_b].map { |result| result.await.to_s }.await_all
私は非同期かどうかがキーワードとしてわかるのは便利だと感じています。型を明示的に書く必要がないJavaScriptでも、asyncキーワードがあることで非同期処理かどうかがわかり、実行時のエラーが減っています。
LSP を作ったことがないのでわからないですが、末尾につけるよりはキーワードになっていたほうが、await 忘れなどに関する注意を作りやすかったりしそうです。
と、書いてみたものの async def
か .method.async
かはともかく、実行時のエラーが減らせる書き方であればうれしいものです。先ほどkateinoigakukunさんに質問した文脈でも気になるので、取り上げてみました。
ruby.wasm の今後について妄想する
WASIを含め、ruby.wasmはブラウザだけではなく、CDNでも使えるようになってきました。 2022年は構想段階でしたが、どんどん実用化が近づいている印象です。
プロダクトで実用例をうまく出せていないのが悔しいところ!
個人的には Rubyを実行するDiscordのbotを作ったり、ちょっとした文字列の操作に使ったりしていました。
今回の kateinoigakukunさんの発表、RubyGems on Ruby.wasmでは、ブラウザ上で mastodonサーバー(!)が動く様子が紹介されていました。
mastodonはRailsで動いているので、Railsがブラウザ上で動くということになります。
リポジトリを見に行くと、52 file の変更で動かしていることがわかります。
発表にもありましたが、この技術があればブラウザ単位でPull Request単位の Staging(Preview?) 環境を作ることができるかもしれません。 多くの開発者がブランチを作っているような企業では、インフラコストの削減につながりそうです。
また、秘匿性の高いデータの扱い方にも面白いアプローチができるようになったりするのでしょうか。実体となるサーバーをブラウザに渡しているのであまり安全ではないか。
ブラウザに近いということで、JavaScriptとの親和性がもう少し高まるかもしれません。
個人のブログでもいろいろruby.wasmをベースとした記事が上げられています。ruby.wasm ユーザがハックに挑戦した体験をもとにした、面白いFrontend Framework on ruby.wasm の登場を期待しています。ていうか作りたい。
先ほど紹介した、 ledsun さんの発表では、 OrbitalRing というフレームワークを作った話がありました。
Ruby をコンパクトにするためgemを切り出すという作業も進んでいます。
この成果は mruby, picoruby, ruby.wasm, kompo のような、コンパクトなRubyを求める環境への影響がありそうです。
なぜ FUSSY として参加したのか
ここまではRubyKaigiを通じての話をしていきましたが、なぜスポンサーでもないFUSSYという企業で、会社員として参加したのかについて述べていきます。
特にオフラインでの参加の理由を知りたいという人の参考になると幸いです。
先に必要な背景を説明すると、現在のFUSSYは、3人という少ないメンバーで構成されています。いわゆるエンジニアは私1人です。
社内で私に与えられている目標の1つに「技術で長期的に事業に貢献する」というものがあります。
また、私たちは社名と同じ名前の「FUSSY」というWebサービスを提供しています。
サービスをベータリリースして1年、正式リリースしてまだ半年も経っていません。
このサービスのバックエンドは Rails を利用しています。
このような背景で、交通費や宿泊費、チケット代を会社に負担させ、FUSSYのエンジニアとして私が RubyKaigi に参加した理由は大きく分けると以下の2つです。
- 最先端のRubyを追いかける
- 他のRubyistの視点を知る
最先端のRubyを追いかける
RubyKaigiには、Ruby のコミッターをはじめ、Rubyの最先端で挑戦している人たちが集まります。
きっと同意してもらえると思いますが、プログラミング言語の最先端で挑戦し続けるのは本当に難しいです。しかし、年に1回のRubyKaigiで、Rubyのコミッターはどんな課題を感じて、どう解決しているか、コミッター以外の人たちはどんなことに挑戦しているかを知ることができます。
FUSSYのバックエンドはRails なので、Railsがどう進化するか、周辺のgemがどう進化するかは、Ruby自体の進化と密接に関わっていると考えています。
たとえば、Fiber Scheduler の実装が進んだことで async gem ができ非同期実行に選択肢が増えました。もちろんこれはカンファレンスに参加しなくても、わかることです。参加ブログでもたくさん書かれるでしょう。しかし、それらを作成している人を間近で見て、話を聞くことは、親近感が湧き、普段できないような質問や提案をすることができたり、新しい挑戦をはじめるきっかけに繋がりやすいと思っています。[1]
個人で情報を収集するよりもカンファレンスに参加することは、圧倒的にコスパがいいと思っています。
他の言語について、たとえば TypeScriptについて、同様に情報を収集するためには、多くの英語の記事を調査して読む必要があります。どこで誰の話を読めばいいか調べるのも大変です。たとえば、私個人は英語の読み書きのコストが高く、日本語での情報検索に比べて疲れたり時間がかかっています。
RubyKaigi なら、旅費+チケット代で、最先端の情報の多くを母語で得ることができます。コミッターや他の参加者に質問するチャンスもあります。
そして KaigiEffectとも言われますが、カンファレンス後は、新しい挑戦ができるような気がしてきます。会議中やその後にrelineやtypeprofを読みに行った人は多いのではないでしょうか。
他のRubyistの視点を知る
FUSSYは利用者も増えつつあり、今後も成長し続けられると信じています。10年後も開発を続けているつもりです。
「技術で長期的に事業に貢献する」という目標を達成するには技術そのものと、その技術を使っている人についての理解が必要だと考えています。
そのためには、色んな意見が欲しいです。
- フリーランスでいろんな現場を見てきた人
- 同じ現場でずっと開発を続けている人
- 自分と同じように少人数で開発して(私はまだ到達していない!)成功している人
- もうコードを書いていなくて、マネジメントに専念している人
- 技術を広報している人
など、様々なバックグラウンドを持つ人がRubyKaigiに参加しています。 参加者と今悩んでいることや、今日のセッションで良かった話をすることで、自分の視野が広がっていると感じます。今回は何人かと法律に関してや、組織をスケールアップさせるために取り組んだことを相談できる機会があったのが良かったです。
普段直接話さない人と、コミュニケーションするという点で、私は「インターネットでやればいいじゃん」という立場に立てません。どちらかというとオフラインのほうが、話しやすいです。「校長先生の話と同じで誰も聞いてない」という表現も見ますが、校長先生と同じ壇上で話すのはどう考えても緊張します。
オフラインで一人でいる人に話しかけることが、受けるダメージが少ないです。
--
カンファレンス参加の成果が、開発にいい影響を及ぼすには時間が掛かるし、数値指標で測るのは難しいでしょう。
しかし、開発に対するモチベーションが上がり、新しい挑戦をはじめるきっかけになっているのを実感しています。
今後もRubyKaigiに参加し続けたいと思っています。
おわりに
興味を持った分野について、RubyKaigiを通じて学んだことや感じたことをまとめました。
正直言って、まだまだ知らないこと・理解できていないことも多いですが、参加する度に理解が深まっていると感じています。
今回不足していると感じた部分を次回までにキャッチアップし、より濃密な時間を過ごせるようにしたいです。
振り返ると、mrubyの発表を聞きに行けなかったのが心残りです。
また、記事の構成上、紹介しづらかったのですが、特に良かったと感じるセッションを手短に紹介します。
- 金子さんの The grand strategy of Ruby Parser
- 私の中で金子さんが Parser Generator を作っているイメージはあったのですが、今回の発表ではより全体的な戦略像が示されいる点と、実現のために周りを巻き込んで進めている様子がわかってよかったです
- SmartHRさんで行われた事前勉強会で、ド素人質問をしてしまったのですが、その時の質問に対しても丁寧に答えてくれたので感謝しています。おかげで発表前半の理解が深まりました。前回は新しく出てくる言葉についていくだけで精一杯だったので…。
- ima1zumi さんの Exploring Reline: Enhancing Command Line Usability
- 他のセッションはなんとなく扱う題材がわかったのですが、Reline については全く知識がなかったので、聞きに行きました。ゴソッと抜けていた部分が見つかりました。
- 特に、Cursor Back できないデモが印象的で、一気に引き込まれました。ありがとう全ての Command Line Editor, そして Reline。
- mikik0 さんの Spec を書いてくれるツールOmochiの紹介(LT)
- まだ試せていないのですが、面白そうなのでこのあと試してみたいです
- bedrock を使っているようなので、値段が気になるところです
生産者の顔が見えるRubyKaigi本当に楽しいです。もし参加を迷っている方の参考になれば幸いです。
最後に、セッションの合間の短い時間に、廊下での質問に快く答えてくださった kateinoigakukun さん。
このような場を提供してくれた、RubyKaigi のスタッフの皆様や登壇者、参加者に感謝申し上げます。
【読まなくてOK!】採用広告挟ませてください!
FUSSYは、すべてのファン活動を認証し、特別な体験につなげていくプラットフォームを提供しています。
正直仕事はてんこ盛りで、副業できていただけるだけでも、面白い挑戦が出来ると思います。
10月以降で正社員採用もしたいです!公式HPはこちらです。 https://fussy-inc.com
お気軽に funwarioisii までご連絡ください!
-
ところでリモートワークからオフィスへの揺り戻しも近い話だと思います。組織のメンバーの距離感が中途半端に遠いと、なんか進みが悪く感じような気がするという。 ↩︎
Discussion