ククログ

株式会社クリアコード > ククログ > RubyKaigi 2025 - Close Encounters of the dRuby #rubykaigi

RubyKaigi 2025 - Close Encounters of the dRuby #rubykaigi

RubyKaigi 2025に参加して、dRubyに出会った児玉です。

この記事では、次の2つのことについて話します!

  • dRubyとの遭遇
  • RubyKaigi 2025で印象に残ったトーク

dRubyとの遭遇

いきなりですが、dRubyを触ったことがありますか?私は、気にはなってはいたのですが、今回のRubyKaigiまで触ったことがありませんでした。 ひょんなことから、コード懇親会でdRubyのサポートをされていた塩井さんに、同イベントでさんが利用されていたdRubyのテキストを譲っていただきました。これがきっかけで、実際に手を動かして触れる機会を得ました!

実際に読んでみると1ページ目から不思議な世界が広がっており、私は引き込まれました。 ぜひ、この感動を皆さんにも味わっていただきたいので、紹介します!(1ページ目だけ紹介します。)

自分で手を動かして触ってみたい方は、テキストであるdRuby hands-on workshopが配布されているので、ぜひ実際に動かしてみてください!(配布していただきありがとうございます。)

では、実際にテキストの1ページ目に書いてある内容を見ていきましょう。 次のような、hello_server.rbとhello_client.rbがあります。

# hello_server.rb
require "drb"

class Hello
  def greeting
    puts("Hello World.")
  end
end

uri = "druby://localhost:54000"
DRb.start_service(uri, Hello.new)
sleep
# hello_client.rb
require "drb"

DRb.start_service
uri = "druby://localhost:54000"
it = DRbObject.new_with_uri(uri)
it.greeting

次のように実行すると何が起きるでしょうか?

// terminal 1
$ ruby hello_server.rb
// terminal 2
$ ruby hello_client.rb

私の感覚では、hello_client.rbを実行した瞬間に、it.greetingの部分でNoMethodErrorが起きて、エラー終了すると思っていました。ただそうはならないのが不思議なポイントです!

実際に実行してみると次のように、hello_server.rbを実行したterminal 1で、Hello World.と標準出力に表示されます。

$ ruby hello_server.rb
Hello World.

これは、別プロセスに存在するオプジェクトにメッセージを送っていることになります。そんなことが可能なのか?と不思議な気持ちになりますよね。別プロセスのオブジェクトに対して、Rubyっぽくメッセージを送れちゃうのがdRubyなんです! 続きが気になる方(dRubyと遭遇したい方)は、ぜひdRuby hands-on workshopを読んでみてください。

あまりにも不思議で気になったので、RubyKaigiから戻ってきてすぐにdRubyのコードリーディングを始めてしまいました。 なぜこんなことが可能なのかの仕組みについて、現時点での理解を図にしてみたのでそれをベースに話します!

ここから先は、ネタバレをふくみます!

ざっくり大まかな流れとしては次のようになります。

  • hello_server.rbにて、DRbServerを起動し、frontオブジェクトを配置する
  • hello_client.rbにて、DRbObjectに対してメソッドを呼ぶ
  • hello_client.rbにて、呼ばれたメソッド情報をMarshalして、参照先のDRbServerに送る
  • hello_server.rbにて、受け取ったMarshalされたメッセージを復元して、その内容をfrontオブジェクトに対してメッセージとして送る

how-hello-druby-works

DRbServerを起動し、frontオブジェクトを配置する

uri = "druby://localhost:54000"
DRb.start_service(uri, Hello.new)

コードのままですが、localhost:54000でDRbServer(TCP Server)を起動します。 そして、frontオブジェクトとして、Helloクラスのインスタンスを配置します。 frontオブジェクトとは、DRbServerにリクエストを送ったときに入口となるオブジェクトを指します。 (今後はfrontオブジェクトと呼んだ場合は、ここで渡しているHelloクラスのインスタンスを指します。)

how-druby-drb-server-starts

DRbObjectに対してメソッドを呼ぶ

uri = "druby://localhost:54000"
it = DRbObject.new_with_uri(uri)
it.greeting

参照するDRbServerのURLを指定して、DRbObjectのインスタンスを作成します。 このDRbObjectのインスタンスを通すことで、参照先のDRbSever上に存在するオブジェクトにアクセスできます。 今回は、it.greetingとあるように、参照先にあるHelloクラスのgreetingメソッドを呼んでいましたね。 なぜ、この記述で呼べてしまうのでしょうか?ほんとに不思議ですよね。 それでは、その不思議を紐解くためにメソッドを呼んだときに何が起きているのか?を見ていきます。

how-druby-drb-object-initializes

呼ばれたメソッド情報をMarshalして、参照先のDRbServerに送る

it.greeting

DRbObjectに対して、存在しないメソッドを呼ぶと普通はNoMethodErrorになりますが、 method_missingを利用して、次の処理がおこなわれるようにメタプログラミングされています。 呼ばれたメソッド情報をMarshal.dumpして、参照先のDRbServerにメソッド情報を送る処理が行われます。 補足としてMarshalとは、Rubyオブジェクトを文字列(やファイル)に書き出したり、読み戻したりする機能をもつモジュールです。 なのでMarshal.dumpは、Marshalを利用してメソッド情報を文字列に変換しているのです。 そして、その変換した文字列を参照先のDRbServerに送っているのです。 次に、このMarshal.dumpされ送られたメソッド情報は、どう利用されるのか見ていきます。

how-druby-marshal-dumps

余談ですが、実際にWiresharkを利用して送られているパケットの中身をみてみると、メソッドの情報が送られているのを確認できます。(画像の赤枠内をみるとわかりやすいです。)

what-marshalized-method-is

受け取ったMarshalされたメッセージを復元して、frontオブジェクトに対してメッセージを送る

$ ruby hello_server.rb
Hello World.

DRbServerに渡ってきたMarshal.dumpされたメソッド情報は、Marshal.loadで文字列から復元されます。 復元されたメソッド情報は、とくに指定のない場合は、frontオブジェクトに対するメッセージとして処理されます。 ここでは、frontオブジェクトは、Helloクラスのインスタンスなので、Hello#greetingが実行されます。 実行された結果として、「Hello World.」が出力されます! これでどのように別プロセスのオプジェクトにメッセージを送っているのか解明できて、スッキリしましたね。 (dRubyには、DRbUnknownInvokeMethodというクラスやスレッドの管理の仕方など、読んでいて面白い部分が多いので、気になった人は読んでみるのをオススメします!)

how-druby-marshal-loads

最後に、今年のRubyKaigiでは、dRubyをruby.wasmを利用してブラウザ上で動かせるようにした「dRuby on Browser Again!」という発表もあったので、ぜひそちらも見てみてください!

youchanさんとledsunさんの発表資料

RubyKaigi 2025で印象に残ったトーク

RubyKaigiの感想も含めて書こうと思ったのですが、分量が多くなりすぎてしまったので、 今回はバッサリ切って、印象に残ったトークに絞って書きます。

Ruby Taught Me About Encoding Under the Hood

ima1zumiさんの発表資料

文字エンコーディングの歴史からRubyにUnicode 15.1.0対応をいれRubyコミッターになるまでのお話でした。とても興味深い内容でした。私のほかにも、発表を聞いているうちに知らず知らず文字エンコーディングの奥深さに引き込まれた方も多かったように感じました。1つのきっかけを通して好奇心のままに深く掘り下げていく姿勢は、私もぜひ見習いたいと思います。

個人的には、普段開発しているGroongaでも、ノーマライザーのオプションとしてダイアクリティカルマークを取り除く実装をしていたので、合成済み文字(Precomposed characters)と結合文字(Combining characters)のお話になったときはわかる!という気持ちになり嬉しかったです。というのも今までのRubyKaigiではトークの内容に圧倒され、置いていかれることが多かったのですが、今年はそこから一歩進んだ感じがあったためです。

The Evolution of the CRuby Build System

kateinoigakukunさんの発表資料

複雑に入り組んだRubyのビルドシステムの現状と課題が、図解や実際の挙動の可視化によってわかりやすく提示されていました。とくに印象的だったのは、直面している問題の全体像を把握するために独自のgemであるtracemakeを開発し、ビルド工程を追跡・解析している点です。Rubyをより便利にするために自らRubyでツールを作り上げるその姿勢も、ぜひ見習っていきたいです! (発表を聞いていて、Rubyのビルドシステムを触ってみたい気持ちになったので、Rubyを自分でビルドするところからはじめてみようと思います!)

まとめ

今回の記事では、dRubyとの出会いと印象に残ったセッションについて紹介しました。

最後に、私たちが何気なく毎日使っているRubyが当たり前に利用できている裏側には、多くのメンテナーやコントリビューターの支えがあることを改めて痛感したRubyKaigiでした。 たとえば、Windows 2019 Actions Runner Imageの非推奨に合わせてCIを新しいランナーに切り替えることで、Windows上でRubyをテストできる環境を維持したPRがあります。このように日々の支えがあるからこそ、私たちは当たり前にRubyを使い続けられるのです。

単に「ありがとうございます」と言うだけで終わるのではなく、「Rubyを当たり前に使えるようにするには何が必要か?」という視点で、自分にできる貢献を少しずつでも始めていきたいという気持ちになったRubyKaigiでした。

最後に、クリアコードでは、RubyKaigiへの参加を全面的にサポートしてくれます。参加費用の支援だけでなく、このイベントの参加を業務として認め、気兼ねなくコミュニティに貢献できる環境を提供してくれます。興味のある方は、クリアコードの採用情報もぜひご覧ください。