RubyKaigi 2024に参加 & 登壇しました + Rubyアソシエーション開発助成の話

RubyKaigi 20024 RubyKaigi 2024おつかれさまでした! 沖縄から帰ってきてはや一週間余り、ようやく今年のRubyKaigiが終わったという現実を受け入れられるようになってきました。

海が綺麗でしたね

ありがたいことに、わたしは今回もsocketライブラリのHappy Eyeballs Version 2(以下HEv2)対応を題材に登壇の機会をいただきました。

rubykaigi.org

また今年は勤務先のエス・エム・エスがブースを獲得したので、初めてスポンサーとしてブースに立つこともできました。

この記事ではRubyKaigi 2024に至るまでと、それからRubyKaigi 2024会期中の出来事について振り返ってみたいと思います。

※とんでもない長文ですがご容赦ください

Happy Eyeballs Version 2 対応socketライブラリ開発日誌

上記の通り、去年のRubyKaigiからこの一年socketライブラリのSocket.tcpメソッドとTCPSocket.newメソッドのHEv2対応を行なっていました(後者はまだ終わっていません)
RubyKaigi会期中何人かの方から、そもそもなぜこれをやろうと思ったのか、この課題をどうやって発見したのか、質問をいただきました。
実はHEv2との出会いは2021年に遡ります。

かねてからネットワークプログラミングに興味があったのですが、このときに角谷さんからこんなのあるよ、とメンションをいただいたのがmmasakiさんによる2020年度のRubyアソシエーション開発助成(以下Grant)プロジェクトであったruby の標準ライブラリ Socket への Happy Eyeballs Version 2 (RFC8305) の導入でした。
リンク先の最終報告書とメンター報告書を読むと、この時点では「socketライブラリへのHEv2対応の実装方針は一旦明らかになったが、まだ実装は完了していない」という状況であったことが伺えます。
このときはまだ当事者意識ゼロだったので、「socketライブラリにこんな課題があったんだ…?」くらいに受け止めていました。

時はすぎて翌2022年秋、RubyKaigi 2022で趣味のネットワークプログラミング(Packet analysis with mruby on Wireshark - dRuby as example - RubyKaigi 2022)について発表をしたその後のRubyWorld Conferenceの会場にて、しばたさんから「しおいさん、Happy Eyeballsって興味あります?」とお声がけいただきました。
聞くところによると、Rubyにとっての課題のうちひとつとして、このsocketライブラリのHEv2対応も挙げられているようでした。

Ruby の中にある解決できると嬉しい人が多分多いタフな問題 - HsbtDiary(2022-12-14)

えっこれを自分でやる…??これは自分のような趣味ネットワークプログラマが手を出していい代物ではないのでは…????とたじろぎつつ関連のissueをちょっと眺めたり、そもそもHEv2とは何なのかをちょっと調べたり、逡巡しているうちに年を越してさらに翌2023年春、RubyKaigi 2023がやってきました。

このRubyKaigi 2023ではネットワークからちょっと離れてRubyのパーサで色々遊んでみるという話(Implementing "++" operator, stepping into parse.y - RubyKaigi 2023)を発表しました。
この発表は自分にとってプログラミング言語Ruby(MRI)への解像度を上げるという意味ですごく勉強になる題材でしたし、発表自体もたのしくできたのでとても満足しています。

とはいえ実装中も頭の片隅に「もっとちゃんとネットワークにも向き合った方がいいのでは」という思いがずっとありました。
そこへ最終日の翌日、再び角谷さんから「本業のネットワークの方はどんな感じですか」と発破をかけていただいて、そこでやっとちゃんとHEv2に向き合う覚悟が決まったのでした。なお、わたしの本業はRailsアプリケーションプログラマです。

RubyKaigi 2023が終わった後、 DNSの本を読んだり、IPv6の本を読んだり、RFC 8305を読んだり、2020年度のGrantの際のPRのコードなどを読んで実装に必要そうな情報を集めました。
また、2020年度のGrantのメンター報告書では状態遷移をベースにしたHEv2実装の方向性が示されているものの、なぜそれが必要になるのかを自分で理解するため、とりあえずSocket.tcpメソッドにHEv2を実装してみることにしました。

RFC 8305では「HEv2には四つの段階がある」と説明されています。

This document defines a method of connection establishment, named the
"Happy Eyeballs Connection Setup".  This approach has several
distinct phases:

 1.  Initiation of asynchronous DNS queries [Section 3]
 2.  Sorting of resolved destination addresses [Section 4]
 3.  Initiation of asynchronous connection attempts [Section 5]
 4.  Establishment of one connection, which cancels all other attempts
      [Section 5]

https://datatracker.ietf.org/doc/html/rfc8305#section-3

これを自分が読んで受け取ったままに実装した結果、こうなりました。

github.com

上記では名前解決を並行に行うためにThreadを使っていますが、せっかくなのでRactorに置き換えた実装も作ってみました。

github.com

ソースコードを見ると分かる通り、RFC通りに素直に実装しようとすると、loop do ~ endの中に大量の条件分岐が必要になります。
しかも、(発表中にも触れた通り)「名前解決を待っている間に接続が完了した場合」のようなケースですぐに接続済みのソケットを返すことができない、などの問題も解決できていません。
なのですがこの時点ではまだ、2020年度のメンターであったakrさんが提案されているように状態遷移によってHEv2を実装することでこの問題をどうやって解決できるのか、いまいちピンときていませんでした。

さらに、RubyのsocketライブラリでHEv2対応が必要なメソッドには上記のSocket.tcpと、さらに広く利用されているTCPSocket.newの二つがあります。
前者はRubyで実装されている一方、後者はCで実装されており、本格的に対応するとなると後者の実装難易度は前者よりもさらに高くなることは明らかです。

おまけに、わたしは過去にRubyにコントリビュートした経験がなく…というかそもそもOSSにパッチを送った経験自体も数えるほどしかなく、自分の実装したものをRubyの標準ライブラリであるsocketにマージしてもらうためにはどうすればいいのか検討もつきません。

…と、取り組み始めてはみたものの、現実的に開発を進めていくにあたって現状の自分一人でことを進めていくのに限界を感じ、識者の力を借りるべく2023年度のGrantに「socketライブラリへのHappy Eyeballs Version 2 (RFC8305)の導入」というプロジェクト名で応募しました。
この際、2020年度のmmasakiさんによるプロジェクトから得られた知見を生かして改めてSocket.tcpおよびTCPSocket.newへHEv2を導入したい、と提案したところ、ありがたいことに採択の対象となりました。

こうしてGrantのメンターとなってくださった成瀬さんとは、Slackでのやりとりを中心にプロジェクトを進めることになりました。
Grantでのプロジェクトの進め方には特に決まり事はないようなのですが、わたしの場合は基本的には実装中の困り事などをSlackで相談し、そして実装できたものをレビューしていただく、という形で開発を進めていました。
また成瀬さんの他にも沢山のRubyコミッターの皆さんがSlackのチャンネルに参加して時に相談に乗ってくださり、ありがたい限りです…🙏

Slackで成瀬さんとやりとりをしていて理解できてきたのですが、わたしは当初HEv2アルゴリズムのことを「名前解決の段階と接続試行の段階に分けて処理を行う」かのように理解していました。


1. メインスレッドから子スレッドを二つ生成し、各スレッド内でそれぞれアドレスファミリ[a, b]の名前解決を開始
2. いずれかのアドレスファミリの名前解決を待機
3. 先に アドレスファミリaの名前解決が完了
4. aのアドレス宛に接続試行開始
5. aのアドレス宛の接続確立を待機
6. aのアドレス宛の接続に失敗
7. アドレスファミリbの名前解決を待機 -> 完了 -> bのアドレス宛に接続試行開始
8. bのアドレスで接続確立

なのですが実際には、「いずれかのアドレスファミリの名前解決が終わって接続試行を開始した時点で、まだもう片方のアドレスファミリの名前解決が終わっていない」ような場合、接続確立と同時にもう片方の名前解決も待つ必要があることがわかりました。


1. メインスレッドから子スレッドを二つ生成し、各スレッド内でそれぞれアドレスファミリ[a, b]の名前解決を開始
2. いずれかのアドレスファミリの名前解決を待機
3. 先にアドレスファミリaの名前解決が完了
4. aのアドレス宛に接続試行開始
5. aのアドレス宛の接続確立、もしくはbのアドレスの名前解決のいずれかを待機
5-1. ここでもしアドレスファミリbの名前解決が完了した場合は残り時間を待機し、bのアドレス宛に接続試行を開始した後、aかbの接続確立を待機する
6. aのアドレス宛の接続に失敗
7. アドレスファミリbの名前解決を待機 -> 完了 -> bのアドレス宛に接続試行開始
7-1. 5ですでにアドレスファミリbの名前解決が完了し、bのアドレス宛に接続試行を開始している場合、この行は不要。代わりにbの接続確立を待機する
8. bのアドレスで接続確立

上記では省略していますが、実際にはここにIPv6での接続を優先するなどの条件も含まれます。
これをまじまじ見つめていると、HEv2には

  • 処理には段階があり、どの段階にいるかに応じて特定の処理を行う
    • 名前解決の開始、接続試行の開始、接続試行・名前解決の待機など
  • 処理を行った結果によって変化するリソースがある
    • 接続未試行のアドレス一覧、接続中のアドレス(ソケット)一覧など
  • 処理を行った結果、変化したリソースの状態から次の段階が決定する
    • 例: 接続未試行のアドレスが残っている場合は接続試行を開始する段階に遷移する、など
  • 処理の開始地点から何パターンかの道筋を辿り、最終的に成功か失敗かの段階に至る

という性質があることがわかります。ここへきて自分の中でも、これは状態遷移するアルゴリズムなんだな、と理解が追いついてきました。
そこで実装にあたっては、まずはakrさんのこの図を理解して実装に落とせるような疑似コードを作ることにしました。

図 1 Happy Eyeballs Version 2 の状態遷移図

https://www.ruby.or.jp/grant/2020/matsushita_mentor_report.pdf

実際にはこの作業は上記の図と最初の実装を踏まえてざっくり大枠を考えた上、実装と並行して進めていました。
当初はあまりの全体像の見えなさに「まともな人類が触っちゃダメなやつ」との評が挙がる場面もあったりしたのですが、進めているうちに扱うリソースがだんだん明らかになってきたことにより、あとは段階ごとにそれらの条件の組み合わせに応じて遷移先を考える、という作業へ収束していきました。
これは個人的に割と好きな作業でした。

そうして出来上がった疑似コードの全容はこちら

hev2_states.md · GitHub

あとは実装の方をこれに合わせていくように修正していきました。
実際のSocket.tcpの実装はこちらです。

そしてこの変更について発表すべくRubyKaigiにプロポーザルを提出したところ無事にこれがacceptされ、

そしてその5日後にSocket.tcpへの変更がmasterにマージされました。やったー!!!!
マージに至るまでSlackでのやりとりはもちろん、それ以外にもbugsやPRのコメントで識者の皆さんから沢山知見をいただきました。本当にありがとうございます。

ということで、HEv2対応のSocket.tcpを携えて向かったRubyKaigi 2024の発表資料はこちらです。

speakerdeck.com

今回の発表では上記したようなHEv2は状態遷移するアルゴリズムであることと、それをどうやって実装するかについてを中心にお話ししました。
これを紹介するだけで発表時間のほとんどを使ってしまったのですが、実際にはこの他にもおもしろ実装裏話が色々あったので、ご興味のある方はどこかで訊いてやってください…

さて残されたTCPSocket.newの方については、Socket.tcpの実装から得られた知見をもとに、MRIの内部実装固有の事情などを考慮しながらどうやって進めていくかについてRuby 3.3 リリースパーティーの場で成瀬さん、akrさんと話し合いました(といいつつ、実際はお二人の会話についていくだけでいっぱいいっぱいでした…)

(tomogさん写真ありがとうございます!)

こちらについてはGrantの期間中に叩き台はできたものの、スレッドの後処理がちゃんとできていなかったりと詰めが甘い部分が残っているので、引き続き作業予定です。

github.com

github.com

なお、今回のプロジェクトの全体像については7/19(金)開催のRuby Association Activity Report(オンライン)で報告する予定なので、ご都合が合えば聴きにいらしてください。
最終報告書も後日Rubyアソシエーションの公式サイトに掲載される予定です。

www.ruby.or.jp

はじめてのスポンサーブース

さて話はがらりと変わって、今年、所属先のエス・エム・エスはプラチナスポンサーとしてRubyKaigiに関わることになり、伴ってブースも出展する運びとなりました。
自分個人としてはRubyKaigiへの現地参加はこれで4回めだったのですが、スポンサーとしてブースに立つのは初めてだったため大変緊張しました…

ブース出展に向け、社内ではRubyKaigiに参加するメンバーで定期的に集まり、当日の配布物の内容、ブースでのだしもの、オペレーションについて考えていきました。
特にブースでのだしものについて、あまり背伸びせず自分たちらしいものを出すとしたらどんなものだろう?という発想から、やっぱり普段の開発の様子を見てもらうのが一番なのではないか、という話になり、実際に自分たちが普段書いているソースコードをそのまま会場で公開することになりました。
実際に会期中、ブースに立ち寄ってコードを見てくださった方々からは割と好評なフィードバックをいただいていたように記憶しており、これは大正解だったのではないかと思っています。

あと、社内に缶バッジメーカーがあったことから参加者の皆さんのSNSアイコン缶バッジを作成する企画も開催しました。
こちらも多くの方から申し込みをいただき、ありがとうございました!

締め切り後に社内で手作りしました。缶バッジメーカー自体は会社に一台しかないのですが、アイコンを印刷する、円形に切り抜く、缶バッジメーカーにセットする…といくつか工程があったので、並列化手法でいうところの専門家並列法で手分けして作業してました。

その他にも諸々の発注や買い出しや調整や打ち合わせを普段の業務の傍ら皆で手分けして取り組み、特にかとりえさん、st_1tさん、しんくうさん、takuyakodama39さんがいなければこんなに充実したブース企画を出すことは難しかったと思います。本当にお疲れ様でした。
また、RubyKaigiとブース設営に造詣の深いryopekoさんがアドバイザーとして関わってくださったのもとても心強かったです…!

これは沖縄へ送る荷物を会社から一通り発送した後のつぶやき。

RubyKaigi 2024 参加日誌

さて、ここからはそうしていよいよ迎えたRubyKaigi 2024の様子です。
(以降、会期中のつぶやき多め。いくつか他の方のも引用していますので、もし問題がありましたらお手数ですがお知らせください。)

DAY 0 (5/14)

皆が話題にしていた空港の看板。記念写真を撮ろう〜と近づいたらその周辺にRubyistたちが看板に吸い寄せられるように集まっていて面白かったです(自分もそう)

この後、たまたま合流した会社のメンバーで国際通りA&Wへランチに行きました。この時は気づいていなかったのですが、このお店が入っていたビルの電光掲示板にRubyKaigiのCM(ぺんさんの書いたQuine)が流れていました。

お昼ごはん後、会社のメンバーたちはブース設営のために会場へ。「しおいさんは発表準備をしてください」と言ってもらえたため、お言葉に甘えて一旦解散し、宿泊先でちょっと発表練習をしていました。

その後Pre-checkinのために会場に行ったら、すでにブース設営は完了していた…

今年はこのPre-checkinの仕組みがあったため、DAY 0から会場でRubyistたちの熱気を感じることができ、翌日からはじまるRubyKaigiへの期待が否応もなく高まりました。

その晩は永和さん主催のESM Night Cruise at RubyKaigi 2024(ESM Night Cruise at RubyKaigi 2024 - 株式会社永和システムマネジメント | Doorkeeper)に参加しました。2019年のRubyKaigiの博多湾クルーズのときは参加できなかったのでありがたい…

船上では久しぶりの人々と色々お話しした他、初めましての人々とも知り合うことができました。
外は大雨でしたが、それはそれで面白かったです。

DAY 1 (5/15)

初日。
会場近くで朝ごはんをいただこうと入ったお店にて、ドアを開けると早速Rubyistたちがわいわいしていたので、一緒に朝ごはんをいただきました。

おいしいコーヒーをいただけたのでDAY 2以降もお邪魔しようかな、と思っていたら何とこちらのお店、翌日から梅雨休みに入ってしまわれました…

会場着。ogijun業をされている角谷さん。

今回の会場であった那覇文化芸術劇場 なはーとは3年前に開館したばかりの新しい会場とのこと。メインホールは沖縄の海の中を思わせるようなデザインで格好良かったです。

メインホールに松田さんが登場。ついに始まります。

この後はスポンサーLTの後、ぺんさんによるKeynote
前半でWeirdなCodeの書き方を色々レクチャーしてくださっている時点ですでにう〜ん?となっていたのですが、後半でひとりTRICKが始まって爆笑してしまいました。
次々ととんでもないコードが出てくるばかりか、それに引っ掛けて他のトークの紹介もあり、これからはじまるRubyKaigiへのわくわく感が高まる素晴らしい基調講演でした…!!

この日の最後の時間帯が自分の発表の出番だったのですが、ぺんさんの発表を見てなぜかこんな精神状態に。

その後のLunch Breakでは、STORESさん主催のSTORES CAFE for Womenにて他の参加者の人々と一緒にランチをいただきました。
初めましての方々と一緒にテーブルを囲んでお話しできる機会はなかなかないので、こういった機会をいただけるのはとてもありがたいです。おかげで新しいrubyfriendたちができました。
が、この日は色々(?)あって休憩時間の方がぎりぎりになってしまい、写真を撮ったりするのを失念しておりました。ごはんは大変おいしかったです!!!!

この日はこの後、こんな感じで過ごしました。

  • 金子さんのThe grand strategy of Ruby Parserを聴く
    • タイトルの通りThe "grand" strategyによって描かれるLrama製パーサの未来への道のりのお話。しかもその未来は、金子さんとLramaに関わる人々の手によってもう割と近くまでやってきているというのを感じました
    • 金子さんのLRパーサとparse.yへの愛情も垣間見えてよかったな〜。ちょっと齧っただけの身でこんなことを言うのは烏滸がましいですが、わたしもparse.y好きです。
  • YokooさんのCross-platform mruby on Sega Dreamcast and Nintendo Wiiを聴く
    • 前回登壇されたRubyKaigi 2022のときは聴けなかったのですが、TLが大盛り上がりだったので今年こそはと聴きに行ったところ、噂に違わぬ面白さでした…!!
    • ゲーム機全然詳しくないのですが、Yokooさんの情熱が伝わってきました。mrubyでC APIをラップすることでそこにRubyを書ける世界を構築するの、夢が広がりますよね…

please use a Dreamcast, Wii, or an emulator for them to view it

😂

  • モリスさんのNamespace, What and Whyを聴く
    • Grant仲間のモリスさん。
    • 実装の話のさわりを今回初めて聴き、すっっっごい大仕事をされている様子が伺えました。これが入るともしかするとRubyの文化圏にひとつのパラダイムシフトが起こるかも、という機能なので、本当にすごい。
    • 発表の中で言及していただきありがとうございました(びっくりしました)。何度も言っていますが、わたし自身もモリスさんをはじめとするAsakusa.rbの人々にシビれたりあこがれたりして今があるので、モリスさんがかつて我々に見せてくれたものが一旦わたしを経由して、形を変えてモリスさんご自身のもとに返ってきたのだと思いますよ…
  • Afternoon Breakの時間は通訳打ち合わせへ。今年もお世話になりました🙏
  • いまいずみさんのExploring Reline: Enhancing Command Line Usabilityを聴く
    • やること(GNU readlineとの互換)をやるために真正面から課題を倒していく、いまいずみさんの格好いいお話でした
    • ステップバイステップでundoの実装を追うことができたので、発表もとてもたのしかったです。こういうスタイル大好き。
    • relineが成長していってirbがどんどん便利になっていくの、ありがたいなあ
    • もしや打ち合わせの時間と重なるかもと心配していたのですが、開始直後のタイミングで滑り込んで無事に聴くことができました(会場は満席👏だったので、運営の方に案内していただいた通路で座り見しました)

その後はいよいよ自分の出番でした。緊張で直前まで舞台袖で震えていました。何度やってもこの有様です。

発表自体は前日の練習の成果か、デモを含めてスムーズに終えることができたような気がします。
クライアントソケットの接続性の改善という、ある種渋めの内容にも関わらず多くの方が聴きに来てくださっていたようで、本当にありがとうございました。
部屋に入れなかった、という方もいらしたようなので、もしよければ後日アーカイブなどをご覧いただけるととても嬉しいです。

DAY 1終了後、Offical Partyのために波の上ビーチへ。

発表が終わった解放感で解放感をtypo

今年初めて出会った人々、去年のRubyKaigiぶりに会った人々、自分が聴きに行った発表者の人々、Rubyコミッターの皆さん、自分にとっておなじみの大好きな人々と、日暮れていく海を見ながら沢山お話しできました。

Official Party後はmoroさんと一緒にこちらにお邪魔してました。

時間の経過とともにどんどんお店の中のRubyist濃度が高まっていって、RubyKaigiを感じました。

DAY 2 (5/16)

朝からビーチを散歩していました。

帰り道、反対方向へビーチに向かう桐生あんずさんとすれ違ってご挨拶したのですが、どうもあんずさんはやんちゃクラブの収録の出待ち待機のためにビーチに向かっていた様子で、自分もあのまましばらくその場にいたら収録に立ち会うことができていたかもしれません。惜しいことをしました(?)

この後は朝ごはんをいただいて会場へ。この日はこんな感じでした。

  • 開場からKeynoteまでブースを担当。この日からスタンプラリーが始まるため、朝から盛況でした。
  • SamuelさんのKeynote Leveraging Falcon and Rails for Real-Time Interactivityを聴く
    • Real-Time Interactivityの歴史からsocketlyプロダクト群の活用例としてのFlappy Birdの実装の解説まで。
    • Samuelさん、「Technology is fun」ととてもたのしそうにコードの解説をされていて、聴いているこちらもわくわくしました
  • ydahさんのDoes Ruby Parser dream of highly expressive grammar?を聴く
    • Lramaチームのydahさん。
    • parameterizing rulesの導入によってあのparse.yが「たのしいparse.y」になっている様子が伺えて、ああ、これがLramaチームの目指したい世界なんだな、と感じました
    • これまで「たのしいRuby」のたのしさを担保するためにparse.yがだいぶがんばっている側面があったと思うので、そのparse.yがこういう形で進化していくのはすごいことだなと思います

くらっている様子

この日は休憩時間を中心にブース当番だったので、ランチタイムはブースでスタンプ(シール)を押したり(貼ったり)、ノベルティを案内したり、ソースコード公開の様子を見守ったりしました。

ブースに寄ってくれる人々とお喋りするのがたのしくてうっかりお昼を食べ損ねるところだったのですが、かとりえさんが沖縄感溢れるいなり寿司を恵んでくれたおかげで事なきを得ました(写真撮影を失念)

こんな場面も。

その後は

  • はすみさんのUnlock The Universal Parsers: A New PicoRuby Compilerを聴く
    • universalなパーサとは、という問いにはすみさんの視点からそれを実現しようとされていて、動機づけも含めて格好よかったです。
    • とにかくメモリを消費するやつら(GCVALUE・IMEMO)をばったばったと薙ぎ倒すやり口がすごかった。こういうお話が聴けるからRubyKaigiはたのしいですね。
  • koicさんのRuboCop: LSP and Prismを聴く
    • 最近使っていないのでキャッチアップできてなかったのですが、RuboCopをLSPで使えるのは革命的な気がします。とはいえリアルタイムにコードを解析することでこれまでになかった課題に取り組む必要もあるとのこと…
    • koicさんのここまで362日の活動と、RubyKaigi 2024後の次の362日に向けた活動の一端が見えるご発表でした
  • Afternoon Breakでは引き続きブースに立ちました。前職の人々が来てくれたのでこの辺りで記念撮影をしたような記憶がある。
  • ahogappaさんのIt's about time to pack Ruby and Ruby scripts in one binaryを聴く
    • Rubyの可能性が未来に広がるお話で最高でした。これこそまつもとさんがよく仰っている「どこでもRuby」の体現ではないでしょうか。デモもよかった。
    • まだいくつかの大きな仕事が残っているとのことですが、Rubyの文化圏にとっての重要な一ピースではないかと思うので、今後とも応援したいです。
    • 実はいつかのAsakusa.rbミートアップで、こういうものを作っているんですよね、とahogappaさんが仰っていたのを聞いていました。RubyKaigiの舞台でお話を聴くことができて、胸熱です…
  • sylph01さんのAdding Security to Microcontroller Rubyを聴く
    • PicoRubyが「本物のIoT」を実現しようとしている…sylphさんの本領が遺憾無く発揮されていて、たのしそうに開発を進めている様子が伺えたように思います
    • 個人的にRubyKaigiでsylphさんのお話が聴けたらいいなあとずっと思っていたので、それが叶ってうれしいです。参考: RubyKaigi 2024が終わったのでまずはクソデカ感情の処理をさせてください - そんなことはさておいて
    • Team Protocol Implementersとしてうなすけさんと一緒に名前を呼んでもらいびっくりしました。いつもお世話になっております…
  • DAY 2の〆にLightning Talksを聴く
    • 今年も多様性に富んだ濃い味のラインナップでたのしかったです。chobishibaさんの「Enjoy Creative Coding with Ruby」やhachiさんの「Drive Your Code: Building an RC Car by Writing Only Ruby」はすごいいい話で心が洗われました。
    • みっきーさんの「The test code generator using static analysis and LLM」、早速翌日廊下で有志によってcommits to omochi活動が行われている様子を目撃しました。すごい。
    • あと個人的には豪快にタイムアウトして銅鑼が鳴るのもLTの醍醐味だと思うので、そういう点も含めて今年も金子さんのLTは最高でした。もちろん内容も。

皆やっていることがすごいのはもちろんですが、この「本物のハッカー」はどちらかというと自分のやりたいこと、やるべきことを実現しようとする心意気のことを指していました。
わたしは打たれ弱い人間ですが、それでも自分なりのやり方でそれをやりたいんだな、としみじみしていました。

とか考えていたらRuby 3.4.0 preview1 がリリースされていた。おつかれさまです…!!!!

この後は会社のメンバーと、会社からの支援で参加されていた学生さんたちと一緒に晩ごはんへ。
学生さんたちお二人、RubyKaigiに上記のような「本物のハッカーたち」の熱気を感じ取ってRubyKaigiをたのしんでいらしたようなので嬉しいです。

(飲み会の席でミームを教わったりしてました)

解散後はmoroさんと共に、何だかお酒が好きそうなメンバーの集まる席へ…

誰かが「これが本物のWeirdなCodeだ」と仰っていたような、いなかったような記憶があります。
あとmoroさんとぷぽさんが共通の趣味の話題で仲良しになっていて何かよかったです。

DAY 3 (5/17)

再び海へ。この日は、前日初日のOfficial Partyの会場近くまで足を伸ばしました。
会期中は三日ともいい天気で気持ちよかったです。

帰り道に撮りました。可愛くないですか?

三日めはおなじみ、Ruby Committers and the Worldから始まりました。
今年はfrozen string literalの話だったり、GVLをやめる可能性の話の辺りが個人的に気になるところでした。
あとビルドシステムの改善に関する話題になった際、kateiさんが「コマンドファイルとしてもバッチファイルとしても実行できるようなファイルがあって、メンテが大変」と仰っていたと思うのですが、前の晩にそういうのを見た気が…ってなってました。

今年の司会のLeoさん、コミッターの皆さんがいきいきしている様子引き出していて素晴らしかったと思います。

その日のその後、

実は個人的に今回のRubyKaigiでは「沖縄に来られなかった社内メンバーのためにとりいさんにサインいただく」というミッションを背負っていたのですが、かとりえさんのおかげで無事にとりいさんに会うことができて無事にミッションクリアできました。
その前後で一緒にいた人々と。皆いい笑顔。

会場に戻るのがちょっと微妙な時間だったので、かとりえさんと一緒にRuby開発さんのブースでマッサージを受けたりしてました。

Lunch Breakの時間はぱんさん、ぱんさんのご同僚たち、sylphさん、大倉さんとお昼ごはんに行きました。
皆英語話者か日英話者で自分だけ全然英語が全く喋れないという面子だったのですが、仲良くしてくれてありがたや…
この辺りで記念撮影した記憶があるけど写真が見つからないので、きっと誰かのスマホの中、あるいはインターネットの海のどこかにあると思います。


(5/28 追記) sylphさんが写真を見つけてくださいました!


ランチ後、のんびりしていたら次のセッションに間に合わず、次に聴いたのは咳さんのERB, ancient and futureでした。
去年のRubyWorld Conferenceで予習していたERBのお話を聞けてうれしかったです。
最後のブロックのローカル変数にlocal_variable_getを呼んで、取得したオブジェクトを操作する技は、改めて観ていてとってもクールだなと思いました。
そしてERB & dRuby 25周年おめでとうございます。

dRuby人口、Kaigi後に増えてそうでうれしい。

この後は聴こうと思っていたセッションが満席で入れなかったりしていくつかのトークを聴き損ねたのですが、その分会場にいたRubyistとじっくり話し込んでました。

特に島田さんとは、RubyKaigiで見られるようないきいきとしたプログラミング活動は一体何がいいのか、というお話をしていました。
例えばLramaの開発には大きなデザインがあって、それを構成する技術要素があって、関わる人たちは誰に強制をされるわけでもなく各々が自分のやりたいことをプログラミングで実現して、それに対してお互いに敬意を持って感謝をし合っているのが伝わってきて、それは素晴らしいことですよね…というやりとりをしました(自分の記憶)
RubyKaigiという場は、そんな野生のプログラミング活動にスポットライトが当たる場でもあるのだと思います。

その後はまつもとさんのKeynoteへ。
3日間の総括込みで色々とトピックがありましたがNamespaceが入ればメジャーバージョンが4になる(かも)、というお話で自分のことでもないのに心拍数が上がりました。モリスさん応援してます…!!

発表の中でまつもとさんは、「Rubyの改善のためにはコミュニティの力が必要」という旨のことを仰っていました。
RubyRubyのエコシステムに直接関わるようなコードを書くことはもちろん、それ以外にも自分にとっての「たのしいRuby」のコードを書くことだったり、例えばRubyKaigiのような場が開かれることだったり、コミュニティを形作るような活動や、Rubyにお客さん以上の気持ちを持つこと(= Rubyistになること!)もまたその一助になるんだろうな、という気がしています。

そうしてたのしい時間には終わりが来るもので、まつもとさんの基調講演の後はとうとう閉会の時間がやってきてしまいました。

今年のRubyKaigiをつくってくださった、格好良い運営チームの皆さんへ拍手を送りました。
皆さんのniceさのおかげで、RubyKaigi 2024も最高の三日間を過ごすことができました。本当にありがとうございました。

来年は松山。元気にお会いできるとうれしいです。


この後はmovさん主催のAfter Partyにて、咳さんと咳フリークの皆さんという何というか栄養価の高そうなテーブルで一緒にごはんをいただいたり(写真がないけど誰かに撮ってもらった気がする)、こういう感じの二次会に参加したり

最終的にこうなってました(お店の方が撮ってくださった写真)(この後松田さんも加わってました)

www.instagram.com

皆「あと小一時間飲みたいな〜」と言いながら0時過ぎくらいにお店に入り、気づいたら4時を過ぎていたのでRubyKaigiすごいなって思いました。
このときに成瀬さんから聴いたLrama誕生前夜の秘話がよすぎた…

それはほんとうにそう(※小崎さんは二次会で引き上げてらっしゃいました)

DAY -362 (概念) (5/18、5/19)

おまけ。
RubyKaigi後、翌日と翌々日の様子

5/18は午前中、斎場御嶽に向かう人々とご一緒し、Nature of Orderを感じて心の平穏を得たりしていました。

(一応写真も撮ったものの、自分の腕ではあの圧倒的な光景の魅力を残せなかったので心の中に思い描いているの図)

その後は那覇市内をぶらっと散歩したり

まだ那覇Rubyistたちがいそうな気配を感じたので、晩ごはん仲間を募ったところ、

こうなりました。にぎやか!
この晩は色んな人のKaigiEffectの話を聞くことができてわくわくしました。もしかすると来年のRubyKaigiではそんな発表を聴けるかもしれませんね…?

さらに翌日。
そういえばなっちゃんさんが絶賛していた千日のぜんざいをまだいただいていなかったので、宿泊先をチェックアウトした後朝イチで向かうと、

この後は国際通りで実家に送るお土産を買ったりとのんびりしていたら、

あやうく飛行機に乗り損ねるところでしたが、無事に東京へ帰ってきました。

今年もMINSWANのおかげで、とてもたのしいRubyKaigi 2024でした。
一方、帰ってきてから体調を崩している人も多く観測しており、皆さんどうぞお体をお大事に…(わたしは今のところ元気です)

来年もよろしくお願いします!

その他に書き残しておきたいこと① ちりとてちんとHEv2

話は変わるのですが、おすすめされて2007-2008年に放映されたNHK連続テレビ小説ちりとてちん」を観始めました。
朝ドラは観たことがなかったのですが、いざ観始めてみると物語にぐいぐい引き込まれてばっちりはまってしまいました。もうすぐ観終わってしまうので寂しいです。

(すべてがちりとてちんスケールになっている様子)

--- ここからちりとてちんの話 ---

ちりとてちんの主人公・喜代美ちゃんは(一般に朝ドラの主人公と言われてイメージされるような、明るく元気で人々から愛されるような人物像とは対照的に)、後ろ向きで心配性で不器用で未熟で、そしてそんな自分自身にしっかりコンプレックスを抱えているという人物です。
何というか、視聴者である自分自身の中にも確実に存在しているようなキャラクターです。

物語が進んで彼女が年齢や経験を重ねても、別人のように見違えて素晴らしい人物へと成長していくわけではありません。ベースは喜代美ちゃんのままです。
だけどそんな彼女が色んな人や自分自身に向き合ううち、世の中に自分の足掛かりを作って、これだけは自分の本領だと思えるものを自分の中に発見して、悩んだり落ち込んだりとんでもない大失敗を重ねたりしながらもそれに取り組み、決して完璧だったり格好良くはなくても自分の人生だと言えるものをやっていく…というのがこの物語の大枠です。

もう少し大きな視点でちりとてちんを観ると、これは喜代美ちゃん一人で完結する物語ではなく、彼女が取り組むことになる落語という、人から人へと伝えられてきた伝統芸能の大きな流れの中で、それを受け継いで次に引き渡していく小さな流れの一つとしての物語なのではないか、つまりこの物語自体がもっと大きな物語フラクタルな構造の一部になっているのではないか、というのが個人的な見方です。

--- ここまでちりとてちんの話 ---

ちりとてちんナイズされた頭でこのRubyKaigiまでの数年を振り返ってみると、Rubyという大きな流れの中で、mmasakiさんakrさんが始められたsocketライブラリのHEv2対応という一つの流れがあり、それをしばたさんや角谷さんがわたしに渡してくださり、わたしはそれを成瀬さんやRubyコミッターの皆さんと一緒にRubyという大きな流れに還元する、という出来事だったのかなあ、と考えたりしました。
改めて助けてくださったり、見守ってくださったり、背中を押してくださった皆さん、ありがとうございました。
というかまだ終わっていなくてTCPSocket.new対応が残っているので、引き続きよろしくお願いします。

その他に書き残しておきたいこと② 今年の#kaigieffect

まつもとさんのキーノートもそうだったのですが、今回RubyKaigiに参加し、大きな世界観を持ってそこに向かっていく人々の姿を見て、それは途方もないけど格好いいことだなと改めて思いました。
いつか自分の中にもそんなものが生まれてくるような活動ができたらいいな。
がんばります。

その他に書き残しておきたいこと③ いろいろ

他にも塗り箸の話(ちりとてちん)とか中央総武線.rbの話とかハンナ・アーレントの話とか書き足りないのですが、いよいよ書き終わる気がしないのでこの辺りで筆を置きます。誰かどこか飲み会の場ででも訊いてください。

RubyKaigi 2023に参加しました & 登壇しました

皆さんRubyKaigi 2023お疲れ様でした! あっという間で本当にたのしい3日間でしたね。わたしは一週間が経ってもいまだにわくわくした気持ちで日々を過ごしています。

今年もありがたいことにDAY2に登壇の機会をいただいたので、この記事では今回作ったものや会期中のあれこれを振り返ってみたいと思います。

今回の発表テーマを選んだきっかけ

今回はImplementing "++" operator, stepping into parse.yというタイトルにて「"MRIにインクリメント演算子を追加する"という取り組みを題材に、MRIの字句解析器(スキャナ)と構文解析器(パーサ)に親しむ」というテーマでプロポーザルを提出しました。
(今年のRubyKaigiはパーサ関連の発表が豊作だったので、思いがけず空前のパーサブームに加わることができて幸運でした)

自分自身の個人的な技術的興味はネットワークの分野にあるのですが、昨年のRubyKaigiに参加して、もう少しMRIの内部実装に対して自分の解像度を上げたいという気持ちが湧いた、というのがパーサに興味を持つことになったきっかけです。

発表の中で一番伝えたかったことは(発表中にうまいこと言えていなかった気がしますが)、プロポーザルのpitchに書きました。

The Ruby parser is very mature and there is an ambitious project underway to rewrite it.
(注: プロポーザルを書いた時点では金子さんの開発されているパーサジェネレータであるLramaの進捗をちゃんと把握していなかったので何かふわっとした表現になっています)
It made me feel as if parsers were out of reach for me.
But on the other hand, the fact that I was able to modify it, even though I am not a parser expert, is worth sharing to spark people's interest in the parser of Ruby. I don’t want Ruby internals to be unfamiliar to the rest of us.

わたしはRubyが好きなので、自分も含めてRubyの内部実装に親しんだり身近に感じられるともっとRubyがたのしくなるのではないかな、と思いこのようなPitchを書きました。
(その点でいうと人々が名著Rubyのしくみを読みたいと思うモチベーションももしかするとこの辺りにあるのかも…と勝手に思っております)

Ruby++開発日誌

とはいってもそもそも自分自身がMRI初心者なので、一体何から始めれば…と思っていたところ、Fukuoka.rbメンバーであるいでさんが前述のRubyのしくみや今回とてもお世話になったRubyソースコード完全解説(あるいはRuby Hacking Guide、RHG)を読まれていたのに触発されこれらの本を読み始めました。

(実はRubyのしくみはすでに読んだことがあったのですが、何度読んでも自分には難しく、今回が4回目か5回目の挑戦になりました。RHGのパーサの章も最終的には4回くらい読みました)

(あとは今回の題材に直接関係はないのですが、RubyでつくるRuby ゼロから学びなおすプログラミング言語入門を読んだり、WEB+DB PRESSで連載されていた「Rubyのウラガワ」を読んだり、Go言語でつくるインタプリタを読んでRubyで実装し直したりしていました)

ところで、前述のRHG第 8 章「Ruby言語の詳細」「自己代入」の節には以下のような記述があります。

+=があるなら++もあるのかな、と思いきや++はない。なぜだろうか。 Rubyでは代入は言語処理系が扱うものである。一方メソッドはライブラリが実 行するものである。この二つ、即ち変数世界とオブジェクト世界、をきっぱり分けるというのはRubyの重要な特徴である。++を導入するとその区別が 壊れてしまいかねない。というのが++のない理由だ。

(Rubyソースコード完全解説 第 8 章「Ruby言語の詳細」「自己代入」)

つまり、Ruby++がないのは言語デザイン上の都合であり、実装上は足そうと思えば足せる状態にある、ということです。
この実装に挑戦してみることで当初の目的であった「MRIの内部実装に対して解像度を上げる」が部分的にであっても実現できるのではないか、と思い立ちました。

(RubyKaigi直前のAsakusa.rb Welcome Drinkupにて中田さんが「構文解析は言語実装の心臓部」と仰っていたので、結果的に切り口としてはなかなか良かったのではないかと思います)

ということで、Rubyにインクリメント演算子を足すために色々試行錯誤した結果がこちらです。

発表資料

speakerdeck.com

リポジトリ

github.com

発表をお聞きの方にはご存知の通り、上記のリポジトリには4パターンの++演算子の実装があります。

  1. ++Integer#succで置き換える
  2. ++を自前のメソッドで置き換える
  3. ++をスキャナで+=1に置き換える
  4. ++をパーサで+=1に置き換える

発表内でご紹介したのは上記の順通りなのですが、発表後に何人かの方から「実際あの発表順通りに実装したわけではないですよね?」と突っ込みをいただきました。
仰る通りで実際には発表と真逆の順番で実装していったのですが、流れを考えた結果発表上は上記の順にご紹介しました。見透かされていてすごいなあ。

最初の実装

++を実装する…といっても実際には何をすればよいのかさっぱりわからず、しばらくはparse.yやcompile.cやinsns.defあたりを開いては閉じ、宙を眺めるという無為な日々を送りました。

とりあえず思いついた案を並べると、

  • 案1. レシーバを破壊的に変更するようなメソッドで++を置き換える
  • 案2. 字句解析時に++を読み込んだら+=1を再現するような処理を行う
  • 案3. 新しい記号と構文規則を追加し、構文解析時に++を表す記号の並びを得たら+=1を再現するような処理を行う

これらのいずれかに着手する前に、まずは取っ掛かりとして++に一番挙動が近そうな+=1構文解析する際のMRIの挙動を調べようと思い、+=1構文解析ログと照らし合わせてparse.yを読むことに着手しました。

その際金子さんさんからいただいたアドバイスを参考にしたりしながら構文解析ログを一行ずつ読んでいるうち、何かだんだんたのしくなってきてしまい「このたのしさを誰かに伝えたい!」と勢い余って鹿児島Ruby会議02構文解析ログリーディングのたのしみ方についてお話をするに至りました。

speakerdeck.com

構文解析ログを一行ずつ読みながらスタックの状態を一つ一つ整理することによってスキャナとパーサが協調して動作する様子のイメージがつきやすくなるので、これはとてもよい経験でした。

また、この発表資料は発表前、金子さんとそしてRHGの著者である青木峰郎さんに内容の正誤確認をしていただきました。おかげさまでMRIにおける構文解析の様子をざっくり掴むのに便利な資料ができたのではないかと思います。その節は大変ありがとうございました。

(あと鹿児島Ruby会議02もとてもたのしかったです!)

そんなこんなでparse.yの様子が少しずつ掴めてきたのと、+=1への理解が深まったところで最初に考えた案を再検討しました。

  • 案1. レシーバを破壊的に変更するようなメソッドで++を置き換える
    • そもそもIntegerはイミュータブルなので無理そう (→この案は後で3つ目の実装に引き継がれました)
  • 案2. 字句解析時に++を読み込んだら+=1を再現するような処理を行う
    • 要は字句解析時に++を読み込んだら記号tOP_ASGNtINTEGERを返すということ。しかしスキャナは一度に2つの記号を返せないので無理そう (→この案は後で2つ目の実装に引き継がれました)
  • 案3. 新しい記号と構文規則を追加し、構文解析時に++を表す記号の並びを得たら+=1を再現するような処理を行う
    • これは構文解析時にnew_op_assign()を呼ぶだけなので、右辺(整数1)の値を用意できさえすれば実現できるかも?

ということで最初に着手した実装は「案3. 新しい記号と構文規則を追加し、構文解析時に++を表す記号の並びを得たら+=1を再現するような処理を行う」でした。

このとき、+=の右辺となる整数1の値をどうやって作るかについてはちょっと悩みましたが、

  • 整数1を字句解析する際に呼ばれる関数set_integer_literal()が呼ばれてからパーサに記号を返すまでの流れを確認する
  • そのうち整数1のRNodeを作成するため必要そうな処理のみを抜き出す
  • ↑をアクションの中で実行する

と言う手順でこれを実現することができました。

そうして完成したのが最初の実装です(つまり、本発表における完成版のRuby++です)

4. Turn `++` into `+=1` (revised) (by the parser) by shioimm · Pull Request #4 · shioimm/ruby-plusplus · GitHub

裏話として、実は今年は当初30分のフルトークではなくLTの方にプロポーザルを出そうと思っていたため(※1)、当初はここまでの実装で一旦完成、という予定でした。

なのですが、その話を上司のmoroさんにしてみたところ「面白そうなので3つの案のうちなぜその実装を選んだのか、という試行錯誤も含めて30分トークの方に提出してみたら」と提案をいただき、また後日Ruby3.2のリリースパーティの席でも金子さんから「パーサに興味を持つ人は希少なので、LTと言わず30分喋ってください」(※2)とお誘いいただき、それならばとこの題材で30分喋ることができないか考え始めたのでした。
moroさん金子さん、その節はありがとうございました🙏

※1 本編での金子さんのLTがあまりに面白すぎたので、今となっては逆にLTだったら落ちていたかもな、と思っています
※2 金子さんご自身のRubyKaigiでの発表によってパーサに興味を持つ人が急増したっぽいので、結果的にこの言葉はfalseになってしまいましたが…

実装2: ++をスキャナで+=1に置き換える

さて一つ目の実装は完成したのですが、上述のRuby3.2のリリースパーティにて金子さんから「別の実装方法もあるのではないか」と示唆されたこともあり、「案2. 字句解析時に++を読み込んだら+=1を再現するような処理を行う」について実現できないか再検討してみました。

スキャナで+=1を再現するにはスキャナから記号tOP_ASGNtINTEGERを両方返す必要があります。
++という文字の並びを凝視しているうち、ここに++という二つの文字があることを発見し、前方の+tOP_ASGN、後方の+tINTEGERを返すという方法を閃きました。

ということで出来上がったのがこちらです。

3. Turn `++` into `+=1` (by the scanner) by shioimm · Pull Request #3 · shioimm/ruby-plusplus · GitHub

この実装では期待するスキャナの挙動を紙に書き起こしながら案を練りました。
実装中にも思いがけず苦労した点があり、それは当初、スキャナのカーソルの位置に対する自分の認識が間違っていたことによるものです。

/*
    Structure of Lexer Buffer:

 lex.pbeg     lex.ptok     lex.pcur     lex.pend
    |            |            |            |
    |------------+------------+------------|
                 |<---------->|
                     token
*/

( ruby/parse.y at master · ruby/ruby · GitHub )

問題になったのはここ、現在のカーソルの位置よりも一つ手前の文字を参照する部分です。

if (peekc_n(p, -2) == '+') {
  // ...
}

ruby-plusplus/parse.y at 6b4f944aeaa5ec5d1c2c57d6e4e972aa519e6a64 · shioimm/ruby-plusplus · GitHub

「一つ手前」なのでpeekc_n(p, -1)かと思いきや、当初思っていた位置よりも一つ先に進んだ場所にカーソルの読み込み位置があり、peekc_n()の第2引数に-2を渡す必要がありました。

同様のことをしたいと思われた方には是非お気をつけください、とお伝えしたいところなのですが、この実装については中田さんから後日「Note that peekc_n does not consider negative offset.」というコメントをいただいています。素人考えって怖いですね。

(とはいえカーソル位置が実際どこなのかについて注意が必要、という点は知見なのではないかなと思います)

なお、この実装が実際にうまくいったかどうかについては発表でご紹介した通りです。

実装3: Binding#local_variable_setでレシーバを置き換える

ここまで2パターンを実装できてしまった(?)ので、「案1. レシーバを破壊的に変更するようなメソッドで++を置き換える」にも実装可能性を感じ始めてしまいました。
ということで出来上がったのがこちらです。

2. Calling a method with `++` (revised) (`Integer#__plusplus__`) by shioimm · Pull Request #2 · shioimm/ruby-plusplus · GitHub

Integer#__plusplus__メソッドの実装にあたりイミュータブルなレシーバの値を更新する方法に考えを巡らせていたのですが、今回のプロポーザルおよび後日発表資料の英語レビューをしてくださった大倉さんとお話ししていた際、大倉さんから「これがRubyのレイヤなら変数の値を更新するのにBinding#local_variable_setを使うんですけどね」とのヒントをいただいてなるほどと膝を打ち、パーサのレイヤでもそれを実現できないか試してみることにしました。
改めまして大倉さん、ありがとうございました!

しかしいざアクションの実装に入ってみると当該環境を表すBindingオブジェクトを得る方法がなかなかわからず、結果的には最も苦労した実装になりました。
要するに現在の実行コンテキストでself.bindingを呼び出した結果のRNodeが必要なのですが、この時selfを得るためにNEW_SELF()を呼び出してしまうとそのselfは今実行しているコンテキストとは無関係の野良のself(つまりmain)になってしまうためです。

実行コンテキストとselfを紐づけるべくbindingを呼んだ際の構文解析フローを追ってみたり、他にも思いついたこと目についたものを片っ端から試してみたのですがいずれもうまくいかず、selfとは一体何なのかすっかりわからなくなってしまいました。

万策尽きて一ヶ月ほど呆然としていたのですが、ふとRubyKaigi 2010でのあんどうやすしさんのLT、parse.yの歩き方 -ワシのRubyは4式まであるぞ-を観ていると、同じようにアクションの中でBindingオブジェクトを取得しており、そのためにあんどうさんはNEW_VCALL()を使用されているのを発見しました。
そしてこれを試してみたところ、やりたかったことがあっさりと実現できたのでした。なるほど、必要なRNodeはVCALLでしたか…

ということであんどうさんとは直接面識がないのですが、おかげさまで実装が完成したのでこの場を借りてお礼を申し上げます。本当にありがとうございます。

なお、ここまで頑張って仕上げたこの実装の顛末は発表中でご紹介した通りです。

実装4: ++Integer#succを呼ぶ

ここまでの実装でプロポーザルを書き(正確に言うとひとつ前の実装はまだ完成していなかったのですが…)、ありがたいことにapproveをいただきました。

早速発表資料作りに取り掛かろうと思ったものの、上記の三つの実装のうち「案1. レシーバを破壊的に変更するようなメソッドで++を置き換える」と「案2. 字句解析時に++を読み込んだら+=1を再現するような処理を行う」はあまりにもコンテキストが強力すぎて、これをうまいこと説明できる気がまったくしません。

ということで、++を構文的に有効にするまでの一通りの流れを説明する用のシンプルな実装が必要だと思い、これを追加しました。

1. Calling a method with `++` (`Integer#succ`) by shioimm · Pull Request #1 · shioimm/ruby-plusplus · GitHub

ここまで散々苦労してきたので、この実装は10分くらいで終わりました。練度✌️

(ちなみに) 後置演算子++の話

ところで、今回の発表でご紹介しているi++のようなスクリプトは後置演算子なので、++よりも先にiが評価された結果i++の返り値自体はiそのものになるのでは…と言うご指摘を発表後、複数名の方からいただきました。全くもってその通りです。
すみません、そこまでは実装する余裕がありませんでした。iを先に評価する、というのはもう一段階挑戦が必要そうな気がするので、今回の発表でパーサに興味を持ったどなたかに試してみてほしい…

(ちなみに) 最終的なスライド枚数

ここまでの実装についての解説にスキャナとパーサの一般的な挙動の解説を加えて発表資料を完成させたところ、最終的に今回のスライド枚数は182枚になりました。過去最多!
上述の通り発表資料の英語に自信がなかったため大倉さんにレビューしていただきました。お手数おかけしました…🙏

RubyKaigi 2023 参加日誌

さて、ここからはそうしていよいよ迎えたRubyKaigi 2023の様子です。
(以降、会期中のツイート多め。いくつか他の方のツイートも引用していますので、もし問題がありましたらお手数ですがお知らせください。)

DAY0 (5/10)

あずさに乗って出発。

松本駅に到着。お出迎えをいただきました。

この日の晩は現地の銭湯、塩井乃湯へお邪魔しました(Twitterでずっっっと「之」とtypoしていてすみません…)

大正時代に建てられたという風情のある建物とミネラル分豊富な泉質で体が芯から温まるお湯をたのしむことができる素敵な銭湯でした。
わたしも塩井と申します、という話題からおかみさんとたくさんお話しできたのもうれしかったです。

visitmatsumoto.com

公式サイトhttps://www.mcci.or.jp/www/sioinoyu/


DAY1 (5/11)

女鳥羽川。

珈琲茶房かめのやのモーニング。
松本には行ってみたい純喫茶が行き尽くせないほどたくさんありますね。

会場に到着。たくさんの旗やのぼりが迎えてくれました。まつもと市民芸術館はとても素敵な会場で、特にメインホールは迫力があり、参加者としても気持ちが盛り上がりました。

この日はこんな感じで過ごしました。

  • Matz Keynoteを聴く
  • 初日のランチは一緒に参加していた会社の人々のうち、松本出身のメンバーの紹介で美味しいお蕎麦をいただきました。お店の名前を失念…
  • 休憩中に五十嵐さんからRubyとRailsの学習ガイド2023を購入。これはWebアプリケーション開発の全体を見渡すいい本なので、特に最近Webアプリケーション開発を学び始めたという方におすすめです。
  • ランチ後The future vision of Ruby Parserを聴く
    • 自分の発表でも大変お世話になった金子さん。個人的に今年一番好きなトークでした。
    • MRIのパーサの現状の課題とこれから先こうなると嬉しい、に対して正面から立ち向かい、次から次へと訪れる困難をばったばったと薙ぎ倒しながらパーサを開発されている様子が伺えて圧巻でした
    • Ruby Parser開発日誌を読んで迎えたので、内容の半分くらいはつかめたかな…??という感じ
    • 難しいんだけどもトークも面白いのですごい
    • パーサジェネレータLramaについては事前にAsakusa.rb Welcome Drinkupでお会いした際に「僕らはエンジニアなので入力(今ある既存のparse.yをどう生かすか)のことも考えないといけない」と仰っていて格好いいなと思いました
  • その後UTF-8 is coming to mruby/cを聴く
    • 文字コードは枯れた技術領域なので、mruby/cに1からUTF-8を実装できるのは嬉しい」と仰っていた文字コード大好きいまいずみさん
    • わたしは文字コード業界に詳しくないのでUTF-8を実装するってどういうことだろう…??と思っていたのですが、実際の取り組みはこつこつ着実に進める王道のエンジニアリングで、それをたのしそうにお話しされていていいなあと思いました
  • その後のおやつ休憩の際、ログ処理について勉強させていただきます、ということでtagomorisさんからFluentd実践入門を購入。当日会場最後の一冊でした!

  • 休憩明けにPower up your REPL life with typesを聴く
    • みんな大好きTRICK 2022 (Returns) Gold Medalist ぺんさん
    • katakata_irbについては以前がFukuoka.rbミートアップにいらしていた際に教わったのですが、その便利さとこれをどうやって実現しているのかさっぱりわからず感動しました。
    • 発表を聴いていて、技術的な側面では全然理解できている気がしないのですが、Rubyの柔軟な文法をサポートするために一つずつ丁寧に仕事をこなしていらしてすごいな〜と思いました
  • 続いてLightning Talksを聴く
    • 全部最高でした
    • 全部最高なんだけど、個人的には金子さんのLTでお腹が捩れるほど笑いました
      • The future vision of Ruby ParserからこのLTへの流れで会場のみんな完全にパーサ大好きになってしまったはず
      • パーサに興味がない方にも面白いトークだったと思うのですが、ちょっとparse.yを知ると更に更に面白いのでぜひ今回パーサに興味が出てきた方はアーカイブでもう一度見ていただきたいです。わたしももう一度聴きたい。
    • あと個人的には今回の銅鑼係だったどみにおんさんによる時間と共に迫り来る銅鑼の存在感が本当に絶妙で、LTの笑いとたのしさを支える隠れた主役だったなと思っています。見事な銅鑼をありがとうございました。
  • 初日のセッションはここまで
  • 夜はOfficial Partyへ。ここで初めましての方や、なかなかお会いする機会のなかった憧れの方や、ちょいちょい顔は合わせるのだけどじっくりお話しする機会のなかった方とたくさんお話しできました。もっと話したかったな〜
    • あと人と人のご縁を取り持つお手伝いができたりした場面もあったのでよかった…


DAY2 (5/12)

この日は朝一で同時通訳の方々との打ち合わせがあったので喫茶店抜きで直接会場へ。
あの大量のスクリプトを捌いてくださった同時通訳の方々にとても感謝しております🙏

朝一で聴いたセッションは咳さんLearn Ractorでした。
一緒に観ていたmoroさんが初っ端の「Concurrency is everywhere」というキラーフレーズにやられていたのがすごいよかったです。わたしは「Ractor間をまたぐ値はdeep copyされる」→dRubyっぽい!!「Ractor.make_shareableされた値はfreezeされる」→DRbUndumpedっぽい!!!!というお話に興奮していました。昨年に続きこれぞプログラマ、というトークで痺れました。

自分の出番は咳さんのすぐ後でした。

前日の金子さんのトークで会場内のパーサ熱が高まりに高まった結果、思いがけず本当にたくさんの方がトークを聴きにきてくださいました。
本当にありがとうございます。部屋に入れなかった、という方もいらしたようなので、もしよければ後日アーカイブなどをご覧いただけるととても嬉しいです。

始まるまでは緊張していたのですが、いざ話し始めてみると会場の雰囲気があたたかかったおかげで、これまでで一番リラックスしてお話しできた発表になりました。
(あとはもしかすると去年の件でちょっとだけ肝が据わったかも…?)

自分の発表の後、この日はこんな感じで過ごしました。

  • Yet Another Ruby Parserを聴く
    • Kevinさんによるもう一つの目玉パーサトークということでたのしみにしていたのですが、ここで痛感する自分の英語力不足…!あと自分の発表直後で気持ちが舞い上がってしまっていて集中できず全体的に自分がだめでした…
    • YARP開発のモチベーションにもなっているパーサに対する課題感はみんな共有していそう、というのは受け取ることができたのですが、そこに対して色んな角度からのアプローチが提案されるのは面白いですよね。引き続き見守りたいと思います。
  • その後のランチ休憩中にとりいさんからユウと魔法のプログラミング・ノートを購入
    • 会場でのちょっとした空き時間に冒頭部分を読み、やさしい語り口に早速ぐいぐい引き込まれてしまいました。帰ってきてからまだばたばたしていて読み進めることができていないのですが、早く続きが読みたい!
  • お昼ごはんは何人かの方とご一緒し、この日はお蕎麦ではなく美味しい焼き肉をいただきました。お店の名前を失念…
    • 時間の都合上、ランチ直後のトークに間に合わず😂
  • ランチ後はとりいさんのReading and improving Pattern Matching in Rubyを聴く
    • こちらも素晴らしいトークでした
    • とりいさんは「普通のRubyプログラマであっても、Rubyの内部実装に触れることでもっとRubyを好きになることができる」と仰っていて、「それ!!!!!!!!!!!」と思いました(わたしはこれを自分の発表ではうまいこと言語化できなかった)
    • わたしの発表ではRubyスクリプト構文木になる前まで、とりいさんのご発表ではRubyスクリプト構文木になった後のMRIの内部実装のお話をされていたので、是非セットでおすすめしたいです

セッションを経て翌日の様子(parse.yとcompile.cは神がかり的所業)

  • その後Fitting Rust YJIT into CRubyを聴く
    • 去年のClosing Keynote SpeakerであるAlanさん(日本語も堪能)による「YJITを色んな環境で動かすためにこつこつやっている」お話
    • やっぱり英語はわからないのですが(悔しい)、終わった後にお話ししていると「時間をかけて、ドキュメントをちゃんと読んで、地道にやっていくしかないんですよね」と仰っていて、どんな偉業も小さいひとつひとつの積み重ねなんだなと思いました
  • 2日目の最後、MaximeさんによるKeynoteOptimizing YJIT’s Performance, from Inception to Productionを聴く
    • やっぱり英語が(三度)
    • 上述のAlanさんとお話ししていた時の感想と重なる部分があるのですが(お二人は同じものを開発されているのだからそれはそう…)、地道に積み重ねをやっていくことを丁寧にお話しされていたと言う印象でした
      • 例えばYJITのパフォーマンス最適化のためにまずはYJIT用のベンチマークツールを用意する、というような話は正に""エンジニアリング""という感じで凄みを感じました
    • YJIT、まだまだ伸び代がありそうですごい
  • この日のセッションはここまで
  • 帰る前に角谷さん研鑽Rubyプログラミングへサインをいただきました
    • 研鑽Rubyプログラミングはとても滋味深いよい本なのでまだお持ちでない方はぜひ!!この本からでしか得られない栄養があります!!!(宣伝)
    • 著者であるJeremyさんからのサインはAsakusa.rb Welcome Drinkupの際にいただいていました✌️
      • その際に下手な英語でしたが「素晴らしい本です」とお伝えできてよかった

2日目が終わっての感想。

写真は自分の発表後にmiwaさんからお土産にいただいたhikari no caféさんのおやつです!(自慢)
大切にいただきました。ありがとうございます!

この日はこの後会社の人々と晩ごはんをいただいたのですが、その間にRubyのmasterではLramaがBisonを置き換え(これにより金子さんはいわゆる"The Bison slayer"の異名を得て)、Ruby 3.3.0-preview1がリリースされていました。すごい!!!!

(この夜は本当はもう少し遊び歩きたかったのですが、ほんのちょっとだけ疲労もあり、体調優先で早寝しました)


DAY3 (5/13)

朝は今回Rubyistたちに大人気だった珈琲美学アベへ。
モカクリームオーレとても美味しかったです。

松本市はお水がおいしい」という事前情報を得ていたので毎朝マイ水筒に水を汲んで会場に参じていました。

とうとう最終日、ということで朝一でRuby Committers and The Worldが始まる前にえもりさんやださんからはじめてつくるWebアプリケーション〜Ruby on Railsでプログラミングへの第一歩を踏み出そうを購入しました。

こちらははじめてプログラミングを学ぶ方向けの書籍ではあるのですが、Webアプリケーション、のWebのところに最初からしっかりフォーカスが当たっていてこれは良書だなと思いました。
自分が誰かに(Web)プログラミングについて伝える際(e.g. Rails Girlsにコーチで参加するときとか)に上述の「ユウと魔法のプログラミングノート」と「はじめてつくるWebアプリケーション」を読んでおくといい効果が期待できそう。

(もうお一人の著者であるcobachieさんにもサインをいただく気満々だったのですが、その日のうちにお話しする機会がなくサインをいただき損ねてしまいました。これは松本にもう一度伺うしか…??)

そうして始まった「Ruby Committers and The World」。

今回も最高でしたがパーサの話題だったり正規表現の話題だったりetc...の重要トピックについて議論が交わされ、Rubyの未来についてちょっとしんみりしているところへAaronさんによるRuby 4へのご提案で会場が笑いに包まれたのでした。ちょっと笑いに貢献できて嬉しい。

この後、この日はこんな感じで過ごしました。

  • Build Your Own SQLite3を聴く
    • 「これをこういうふうにこうすればマイコン上でSQLiteが動くんですよ」という、理屈ではそれは確かにそうなのだけど、本当にそれを実現してしまうはすみさんの腕力の強さと技術的面白さに満ちたトークでした
    • はすみさんのお話は面白いのでいつもたのしみに聴いております
  • 最終日のランチは流れで何人かの方とご一緒させていただき、美味しい鴨つけそばをいただきました。やっぱりお店の名前を失念…

  • ランチ後Ruby vs Kickboxer - the state of MRuby, JRuby and CRubyを聴く
    • これをやるんだ、という気概のもとに試行錯誤を繰り返しつつ最高の「たのしいRuby」を実現する、という感じのセッションでめちゃめちゃ刺激的でした
    • MichaelさんSelenaさんのお二人でタイトル通りRuby vs Kickboxerされていました。格好いい。
  • トークの合間に金子さんから一日目のLTの続き(幻のAdvanced編)を披露していただく
    • ここから先がまたとてつもなく面白かった
    • Rubyの柔軟な文法を叶えようと色んなハックで頑張っているのがわかるのでおすすめです。聴いているうちparse.yの向こうに人がいる…!という気持ちになっていました。

  • ここ辺りからちょっと色々ばたばたしていたり、聴きたかったトークが満席だったりして基調講演までホールに戻れず
    • その代わりに色んな人とじっくりお話しする時間をとれたのでそれはそれでよかった…
  • 最後にSoutaroさんによるClosing Keynote Parsing RBSを聴く
    • 空前のパーサブームであった今年のRubyKaigiを総括するかのようなRBSのパーサのお話。Error Tolerant Parser再び。
    • わたしは途中からついていけなくなっていたのですが、Twitter上でパーサに詳しそうな人々がすごくfmfmされていたのが印象的で、パーサへのアプローチは無限にあるのだなと思いました。パーサではないプログラミングもそうなのですが…

そして、Closing Keynoteの後、とうとう閉会の時間がやってきました。

2017年に始まりコロナ禍を経て松本でRubyKaigiを開催するに至るまでの長い道のりと、とうとうそれを実現したNiceなTeamの皆さんが壇上から手を振る姿に、どれだけ拍手を送っても足りない気持ちでした。

本当にありがとうございました。
RubyKaigi 2023は夢のような奇跡のような、あっという間の3日間でした。

今年は初参加の方もたくさんいらしていたという印象ですが、初めての人々にもこの感じを持って帰ってもらえますように。来年また沖縄で集まることができたら嬉しいなと思います。


この後はSTORESさん主催のAfter Partyに参加したり

その後中田さんとゆうぞうさんについていったらその先でこんなことになったり

最終的に懐かしのTama.rbになったり

そして翌朝はこうなる。

実は次の日ものんびり松本観光をしようと街を歩いていると色々とたのしい出来事があったのですが、夕方には無事に帰路につき…

終わってみて一つだけ後悔しているのは、会期中もっと気軽にたくさん色んな人々と写真を撮っておくべきだったな、ということです。
せっかく#rubyfriendsというハッシュタグがあるので、これに託けて来年はもっと写真を撮れたらいいな。

ということで、今年も来年以降もわたしの写真は自由にアップロードしてくださって問題ありません(その際にメンションを頂けると嬉しい!)

来年もよろしくお願いします!

その他に書き残しておきたいこと① 「無名の質」、そしてNice Teamのみなさんへ

Kaigiの間、「RubyKaigiとはいかなる場なのか」を表現するため何度か目にしたり耳にしたり自分でも口にした「無名の質」という言葉があります。
この言葉の出典は建築家クリストファー・アレグザンダーによる「時を超えた建設の道」です。わたし自身は「パターン、Wiki、XP」を読んでいて初めて知りました。

RubyKaigiという場は、端的に言葉で表現しようとすると「たのしい」だったり「最高」のような、それは本当にそうなんだけれどもそれだけではとても言い尽くせないよさを持つ場です。
ある種の混沌の中であらゆることがあらゆる場所であらゆる人の身に、魔法のように同時多発的に有機的に発生していて、それが人々を生き生きとさせているのだと思います。このよさをうまいこと言えないのは、それが名前のつけられない「無名の質」だからなのでしょう。

こうした場を作ってくださったオーガナイザーとヘルパーの皆さん、Rubyコミッターと登壇者の皆さん、そして参加者の皆さんにとても感謝しています。また、自分がそのうちの一人であったことを嬉しく思います。
特に2017年から松本でのRubyKaigiを実現しようと奔走されていたオーガナイザーの皆さんにはこの7年間、大変なご苦労があったと思います。本当にお疲れ様でした。

その他に書き残しておきたいこと② 「同じコミュニティの中の人同士になっていく」ということ

RubyKaigiを終えて改めて感じたことのうち一つです。

RubyKaigiで人とお話ししていると、そのうちだんだん相手が「こういう客観的情報を持った人」でありかつ「自分がいるのと同じコミュニティの人」でもある、と実感できる瞬間があったりして、そうした瞬間がわたしはとても好きです。
それが「コードの向こうには人がいる」を肌身で感じることができる瞬間であるためです。そしておそらくそれは相手の方にとっても同様なのだろうと思います。
わたしはRubyコミュニティに出会うまでずっと人付き合いに苦手意識を持っていたので何か不思議な感じがしますが、こうして人同士が対話をし、同じ時間を過ごすうち「同じコミュニティの中の人同士」になっていくのだな、という気がしています。

(と思ったら3年前の自分がすでにそれを大江戸Ruby会議08お話ししていたのでえらい…)

その他に書き残しておきたいこと③ 2024年に向けて

最終日の翌日に角谷さんから発破を掛けられたのもあり、この後は元々の興味にちょっと方向性を戻して再びネットワーク方面を勉強していこうかなと思っております。
会期中、ゆうぞうさんに「ネットワークの世界は広くて深い沼なので(というかコンピュータの世界全体がそうなのですが)、どこから手をつけたら…」という相談を持ちかけたところいくつかヒントをいただけたので、とりあえず足場からこつこつ固めていきたいです。

まずはそのとっかかりとしてちょうどKaigi直前に公開されていたRubyKaigiとDNS-over-HTTPSとDDRを読んでみたところ、(ちゃんと内容を理解はできている気はしないけど)KaigiのWiFiを支えるNOCの皆さんが自在にネットワークを操っておられる様子に感銘を受け、今の時点では割と苦手意識のあるDNSについてちゃんと勉強してみようと思い立ち、結果こうなりました(※)

引き続きがんばります!

(※後日Cookpadさん主催のアフターイベントでこの記事を執筆された花月さんにご挨拶できてよかったです。その際そらはさんから「異常KaigiEffect」と呼ばれました)

Ruby Advent Calendar 2022 part2 (15日目): 「Webで使えるmrubyシステムプログラミング入門」 (mrubyシスプロ本) 読書日記 (※2年越し)

Ruby Advent Calendar 2022 part2 15日目の記事です🎄
昨日は@rsym1290さんによる「AWS SDK for Ruby V3のスタブを使ってみる」でした。

まえがき

2020年11月25日に発売された udzuraさん著・Webで使えるmrubyシステムプログラミング入門 (mrubyシスプロ本) の読書記事です。

実は本書の執筆中、レビューに参加させていただくという大変貴重な機会をいただいていたのですが、出版当時はまだわたしが自ブログを持っていなかったためにブログ記事を書くことができていなかったのでした…
時は流れて今年、mruby組み込みWiresharkを作ろうと思い立った(参考: RubyKaigi 2022に現地参加 & 登壇しました)際、その実装の参考にしようと再読してみたところ改めてめちゃめちゃたのしく勉強になったため、この機会に大変大変遅ればせながら、2年越しに感想を交えながら記事を書いてみたいと思います。

奇しくも2022年はmruby誕生10周年の記念すべき年でしたね。おめでとうございます🥳

どんな本?

出版社サイトより

本書はシステムプログラミングをテーマに、mrubyの基本と活用法を学ぶことを目的とした技術書です。 システムプログラミングとは何かをはじめ、mrubyの概要、開発環境の構築、コマンドラインツールの実装、C言語とmrubyの連携、Apache HTTP Server にmruby を組み込む方法、安全にコードを書くために必要な知識などを丁寧に解説しています。付録ではシステムプログラミングのためのコマンドラインツールを紹介しています。

上記の通り本書で取り扱っているトピックは非常に広い範囲に渡っているため、mrubyの本として、システムプログラミングの本として、あるいはセキュリティの本として…などいくつもの観点から読むことができます。
mrubyでのプログラミングを通じて、それぞれのトピックを深く学んでいくためのとっかかりを与えてくれるような一冊となっています。

わたしの場合は冒頭に述べた通り、今回はmrubyをWiresharkに組み込みたい、というモチベーションのもとmrubyによるソフトウェア組み込みについて学ぶため再読した際、本書の特にCHAPTER 03の前半とCHAPTER 07が実装のための大きなヒントをくれました。
今後もまた立場を変えて再び別の切り口から本書を開き、新たな発見に出会うことがありそうだなと思っています。

あると良さそうな前提知識

本文中でも明記されているのですが、初めて読み始める前に以下のような知識の土台があるとより楽しめそうです。

各章について

CHAPTER 01: システムプログラミングへの招待

システムプログラミングとはどんなものか、mrubyとはどんなものか、という解説に続いて「本書がどんな人に向けた本なのか」がわかる章です。
わたしは普段Railsを使ったWebアプリケーション開発の仕事をしているのですが、例えばそういった人があえてシステムプログラミングに、あえてmrubyで入門してみることでどんな発見を得られるのか、あるいはインフラエンジニアやSREの方、低レイヤの技術やmrubyそのものに興味がある方へ本書がどのような知見を与えてくれるかが述べられています。

CHAPTER 02: mrubyに触れてみよう

この章で早速mrubyをビルドしてHello Worldしてみたりmgemを利用してmrubyをカスタマイズしてみたりします。環境を用意するところから実行ファイルを作成するまでの道のりが一歩ずつ丁寧に解説されています。
わたしは本書をきっかけに初めてmrubyに触れたため、この章を読んで「rakeコマンド一つで手軽にmrubyをビルドできる」そして「mgemを利用すると自分だけのmrubyをビルドできる」というmrubyならではの体験に感動しました。

CHAPTER 03: mgemを作ってみよう

「mgemを作ってみよう」というタイトルの章ですが、前半は前章を受けてmrubyバイナリがどのようにして実行可能な状態になるのか、そのビルドパイプラインの流れが解説されており、ここでmrubyについての基礎知識を学ぶことができます。
この前半部分は、本書を一周した後で改めてmrubyをちゃんと理解したいという気持ちのときに読み返して点と点が繋がる感覚がありました。

後半はmrubyプログラミングの手始めに、mruby本体に組み込むためのライブラリであるmgemをテンプレート(とても便利)から作成し、テストを追加し、実際にmrubyに組み込んで動作させてみます。
mgemを公開する方法まで解説されているため、実際にmgemを自作したい時にも参照できそうです。

CHAPTER 04: mrubyでシステムの状況を調べる

この章からいよいよシステムプログラミングについての学習が始まります。
導入部分で早速psコマンドやstraceコマンドに触れ、その後プロセスの様子を観察するmgemの開発を通じてLinux/procについて学んでいくことで深淵なるシステムプログラミングの世界に一歩足を踏み入れることができます。
とはいえこの章ではそのためのコードをRubyで書くので、初めてのシステムプログラミングでもとっつきやすく感じました。
また前章に引き続きmgemを開発してmrubyに組み込む、という流れに沿って開発を進めるため、mrubyについては前章までのおさらいもできます。

CHAPTER 05: C言語でmrubyを拡張する

システムプログラミングの深淵にもう一歩踏み込むため、この章ではシステムコール(uname(2)stat(2))とC言語とmrubyのC APIも駆使してシステム情報を取得するためのmgemの開発を行います。
まずはC言語でを扱う簡単なプログラムを書くところから始まり、その後はmgemの中でC言語(mrubyのC API)を用いたRubyプログラミング(!?)に入門することができます。
さらに最後にはgdbを利用してC言語でのデバッグも体験できるという、お得で読み応えのある章でした。

CHAPTER 06: C言語の複雑なデータをmrubyで扱う

この章では、前章でも登場したシステムコールstat(2)とmrubyの仕組みを更に深掘りし、mrubyから扱うことができるようにしていきます。
難易度的には本書の中でも一つの山場のように感じた章でした。mrubyはインスタンスのデータをどのように持っているのか(「Rubyのしくみ」第5章が思い起こされます)であったり、mrubyを介してメモリ管理の仕組みがないC言語レベルのデータをどのように扱えば良いのか、といった難しい話題(自分比)に踏み込んでおり、読むたびに新しい発見があってびっくりしています。
システム情報を格納するStat構造体の持つ各情報に関する小ネタも豊富に詰まっています。

また、この章でも最後にvalgrindを利用してメモリリークの検知を体験することができます。こうした便利ツールの使い方や、プログラムを修正するときの考え方を学ぶことができるのも本書の魅力です。

CHAPTER 07: Apache HTTP Serverの中でmrubyを使おう

ここまでの章ではmgemを作成し、それを組み込んだmrubyを手元で動かしてみる、といった流れで解説が行われてきました。
このCHAPTER 07と次のCHAPTER 08では、いよいよmrubyの本領の一つ、mrubyによるソフトウェア組み込みを体験することができます。 いずれの章でも組み込む対象となるソフトウェアはApache HTTP Serverです。

まず本章ではApacheの拡張機構として書かれたmod_mrubyを実際にApacheに組み込み、RubyApacheの設定を書いてみることによって、「mruby自体をソフトウェアに組み込む、とはどういうことなのか、それによってどんなことができるようになるのか」といったイメージを掴んでいきます。
この章はmod_mruby入門として活用できそうなくらい手厚くmod_mrubyについて解説されているので、そういった用途にも便利そうです。

CHAPTER 08: Apacheの拡張モジュールにmrubyを組み込む

クライマックスの章です。CHAPTER 07では実在のApache拡張であるmod_mrubyをApacheに組み込みましたが、この章では1からApacheにmrubyを組み込んでいきます。
C言語・mrubyのC APIApacheの拡張用APIを駆使してのプログラミング、rakeを使ったモジュールのビルドとインストール、abやperfを使ったパフォーマンスチューニングなどトピックも大盛りです。
rakeタスクの定義は本文中ではさらっと解説されているのですが、この辺りを読んでいて自分がrake(make)について何も知らなかったことがわかりました。

難易度的にもクライマックスなのですがその分勉強になることも多く、Apache以外のソフトウェアにmrubyを組み込むような場合にも非常に参考になりました。
この章がなければWireshark with mrubyは完成しなかったと言っても過言ではない…

CHAPTER 09: 安全なプログラムを書く

最終章は前章までとはちょっと趣を変え、セキュリティのお話です。
C言語でプログラムを書く際に埋め込んでしまいがちないくつかの脆弱性について、そしてそれらの中でバッファオーバーランを例に取り、それを作り込まないための方法論について考えていきます。ここでmrubyのC APIがどのように役立つのかは必見です。
安全なプログラムを書くことの難しさと、それでもそれを目指していかなくてはいけない、という意識の大切さと、そのための実践的な心構えが説かれています。

APPENDIX

CHAPTER 09にてこれでおしまい、めでたしめでたし…かと思いきや、最後に50ページ越えの特大付録がついてきます。
本文中に登場したものを中心に、Cプログラミングやシステムプログラミングの味方となるコマンドラインツールたちについて丁寧に解説されています。便利。

EPIROGUE

謝辞に名前を掲載してもらえて嬉しい✌️
技術者としてmrubyシスプロ本の次のステップを踏んでいくことについてうづらさんの熱い思いが伝わってくるあとがきでした。

おわりに

今年はmrubyシスプロ本とYamanekkoさん著・入門mruby Cからmruby APIを使いこなす(そしてWiresharkの開発者ガイドThe dRuby Book)のおかげでRubyKaigiに登壇できました…本当にありがとうございます。
リファレンス的に参照するなら入門mruby、実践的な使い方を参照するならmrubyシスプロ本、と需要をカバーする本が揃っていてうれしいですね。
mrubyの方は出版時点からバージョンが上がってますます良くなっていっているのですが、いずれも今なお役立つ普遍の教えが詰まった名著だと思います。
普段はMRIを使っているけれど、mrubyってどんな感じ…?という方も、たのしいソフトウェア組み込みの世界を体験する際のお供にいかがでしょうか?

それでは素敵なクリスマスをお過ごしください🎁

RubyKaigi 2022に現地参加 & 登壇しました

しおいです。
みなさまRubyKaigi 2022お疲れ様でした!
わたしはありがたいことに去年に続き、DAY2に登壇する機会をいただきました。

rubykaigi.org

今年は3年ぶり2回目となる現地参加となり、本当に楽しいあっという間の3日間を過ごすことができました。

この記事では、今回のテーマを選んだきっかけ、実際に作ったもの、登壇本番のことや会期中のあれこれを振り返ります。

Wireshark + mruby + dRubyのお話をするに至ったきっかけ

今回は「Packet analysis with mruby on Wireshark - dRuby as example」というタイトルにて「mrubyを組み込んだWiresharkdRubyパケットを解析する」という内容でお話をしました。
こうした登壇テーマを選ぶに至ったのは、去年2021年のRubyKaigi Takeout 2021「Ruby likeなアプリケーションプロトコルを作る」という内容のお話をした際、何人かの方から「dRubyっぽい」との感想をいただいたのをきっかけにdRubyの勉強を始めたことに端を発します。

dRubyはとにかく面白く、またそのときちょうどWiresharkに入門したばかりでもあったため、その年のRuby Advent Calendarのネタとして「dRubyパケットをWiresharkでキャプチャする」という試みを思いつきました。
そうして出来上がったのがこの記事です。

coe401.hatenablog.com

結論を書くと、

  • WiresharkdRubyパケットをキャプチャしようと思ったが、WiresharkdRubyを解析可能なアプリケーションプロトコルとしてサポートしていないので、トランスポートプロトコルまでしか解析できなかった
  • と、いうのは誤解で、後日気がついたところによると実はWiresharkに最初から組み込みのdRubyディセクタをONにすれば解析できた (後日追記)

という内容の記事です。

なお、Wiresharkにおいてはディセクタなるプラグインによってプロトコルごとにパケットを解析できる、そしてそのディセクタは自作することができる、ということは「ネットワークプロトコルハッカーズガイド - キャプチャ、解析、エクスプロイトの理論と実践」を読んでいて初めて知りました。
(ちなみにこの本は良い本なのですがわたしには難しく、一応通読しましたが何ひとつ理解できてません)

ところで、たまたまこのとき同時並行でudzuraさんの「Webで使えるmrubyシステムプログラミング入門」を再読していました。
(こちらも良書です。今回めちゃめちゃ勉強になりました)

この本の中に、Apache HTTP Serverの拡張モジュールにmrubyを組み込んでApacheの中でRubyを扱う、という面白い例が登場します。
ApacheはCで書かれており、そしてわたしが入門したばかりのWiresharkもCで書かれています。
これは、もしかするとWiresharkにmrubyを組み込めばWiresharkの中でもRubyを使うことができるのでは、つまりmrubyを組み込んだWireshark + Rubyで書いたWiresharkディセクタでdRubyパケットを解析できてしまったりするのでは…!?(???)と夢が広がっていきました。Ruby大好きなので。

mruby on Wireshark

ということで実装したのがこちらです。

github.com

Wiresharkにmrubyを組み込むため、Wiresharkリポジトリの中にmrubyのリポジトリをGitサブモジュールとして置いておいて、ビルド時に力技でmrubyをリンクさせるような方法を取りました。
ホストマシンにmrubyをインストールさせてリンクさせる方法も考えたのですが(登壇後にもそのような指摘をいただきました。実際、同じくWiresharkに組み込まれているLuaはそういう方法を取っているようです)、mrubyは柔軟にカスタマイズすることができるため、ユーザーが「Wiresharkに組み込むためのmruby」を常に持っていてくれる保証はないかもしれないと考え、このような方法を選びました。

が、mrubyのリポジトリを丸ごとWiresharkの中に置くのではなく、ビルド済みのlibmruby.aを直接リンクさせる方が良いかもしれない…
この辺りは自分に知見がないために難しく、ぜひ詳しい方にお話を伺ってみたいです。

また何せネットワークもソフトウェア組み込みもdRubyも初心者なので、実装にあたってはC、mruby、Wireshark、CMake、dRubyRubyのMarshalフォーマットの勉強が必要でした。
参考にした書籍・記事・ドキュメント・ソースコードは以下のようになります。

あとmrubyをCに組み込む勉強をしていたときの副産物として、Fukuoka.rb 0x100 回 LT 大会 (#256)でこんなLTをしました。

speakerdeck.com

当初やりたかったことを実現するため結果的にWireshark、mruby、dRubyと話題が発散しすぎてしまったような気がしていたので、登壇前はどれだけの人に楽しんでもらえるかなとちょっと不安だったのですが、登壇後には予想以上の反応、温かい感想をいただきました。
本当に嬉しいです。

RubyKaigi 2022!!

こんな感じで出したプロポーザルが無事通り、準備期間中必死に書いた160枚超の発表用スライドを携え、(ついでにRubyKaigiとは全然関係ないのですがKaigi直前に行っていた転職活動も成功し、そして現職場への引き継ぎも何とか無事終えて、)RubyKaigi本番に臨みました。
(以降、会期中のツイート多め)

会場に着くと、当たり前ですがそこには沢山のRubyistたちが集っていました。
久しぶりに会う人や、初めてin personで会う人や、憧れの人までも。
3年ぶりに人々と顔を合わせ、おしゃべりをし、一緒に難しい話を聴く(そしてその難しさにスッと置いていかれる)、そして現地の美味しいものをいただく、というのはこんなに楽しいことだったのだな、と胸がいっぱいになりました。

初日の休憩時間中、現職の上司と同僚そして先に退職された先輩と同僚と一緒に撮っていただきました。

DAY2はわたしの登壇日でもありました。

本番でお話しした「Packet analysis with mruby on Wireshark - dRuby as example」の資料はこちらです。

speakerdeck.com

RubyKaigiの会場でお話しするのはこれが初めてだったために緊張で震え上がっていたのですが、何とか発表が始まりスライドを進めてちょうど中盤あたりに差し掛かったところで、何とフレッツ光の故障によるネットワーク障害が発生。
オンライン参加の方向けの中継が停止してしまい、わたしの発表はそこで一旦中断となりました。

中断中、不測の事態の発生にわたし自身は内心激しくアワアワしていたのですが、後でTwitterを見ると、会場にいた方にはその動揺っぷりはあまり伝わっていなかったようで安心しました。
また会場スタッフの方が舞台の裾に捌けるための準備をしてくださっている間に、観客席の方から

など続々と質問の声が上がり、それにわたしが答えるという思いがけないコールアンドレスポンス(????)が発生していました。
そのやりとりや、やりとりへの反応も含め、会場のMINSWANから温かく見守っていただいているのだな、と思うとじわじわ気持ちも落ち着いていきました。

その後一旦舞台の裾に捌けたものの、すぐにネットワークが回復する目処が立たなさそう、とのことでオンラインでの中継を中断したまま発表を再開。
このときにはだいぶリラックスできていたため、最後のデモまで無事に完走することができました。何なら普段の発表よりも良かったのでは。

(最終的に次の時間帯のセッションまでネットワーク回復せず…↓)

オンライン参加の方には中断時点で発表が終わってしまった形になっており心苦しいのですが、後日アーカイブYoutubeのRubyKaigiチャンネルにアップロードされるとのことなので、もしよければそちらで楽しんでいただけると幸いです。

(2022年11月4日追記: 動画が公開されました!)

www.youtube.com

またRubyKaigi運営チームの皆さん、あと会場スタッフの方がこうした事態に対応するために色々と手を尽くして下さっていたことに感謝しています。本当にお疲れ様でした。

発表前にツイートで資料を案内するも、下書き状態だったという痛恨のミス。

発表後、沢山労いのお声をいただいたのもありがたかったのですが、それに加えて途中のトラブルのことだけではなく発表の内容そのものについても「この機能はこういう場面で使えそうかも」「ここはもっとこうするといいのでは」「これって〜ということ?」「面白かった」などなど感想や質問をいただけたのは本当に嬉しかったです。

MatzさんにRubyとmrubyを作ってくださったことへの感謝を伝えることができました!

3日目にもなるとだいぶ体力の残量が減ってきているものの楽しすぎてテンション収まらず

最後は松田さんのクロージングトークを聴き、思わず涙ぐみながら夢のような3日間を終えました。
来年はもっと安心して、人々がRubyKaigiに参加できるような世界になっていれば良いなと思います。

松本で無事にお会いできますように!

その他に書き残しておきたいこと① 会場で聴いた発表について

今年も刺激を受けるトークが目白押しでした。個人的には

あたりが刺さっていますが、現地で聴けなかった気になるものもまだ沢山ある!!

その他に書き残しておきたいこと② #rubyfriends

わたしにとっての初めてのRubyKaigiは3年前、2019年に福岡で開催されたRubyKaigiで、当時の自分はまだ仕事を始めたばかり、Rubyコミュニティに顔を出し始めたばかりのプログラマ1年生でした。
その際も会場や懇親会の場で沢山の参加者の人々とお話できて感激していたのですが、それから3年経ち、今回のRubyKaigiではその時よりも更に更に、もっと沢山の人々と一緒にRubyKaigiを楽しむことができました。
この3年を過ごすうちに、自分はこんなに沢山の人々と交流し、あるいは新たに出会い、お世話になっていたのだな、と思うと何だか込み上げてくるものがありました。

今回会場で初めてお会いできた方、あるいは会場でお話しする機会がなかった方、そしてオンラインで参加をされていた方とも、来年のRubyKaigiもしくは別の場所でまたお会いできると嬉しいです。

その他に書き残しておきたいこと おまけ

自分の登壇の中断中、「いやー逆に緊張がほぐれてきました」などと口走っていた記憶があるのですが、実はその時が緊張のピークでした。嘘ついてすみません…
あまりの緊張に壇上で余計なことを言っていなかったか、今更ながらかなり心配しています。

プロを目指す人のためのRuby入門[改訂2版] (チェリー本) を読みました

11/29に発売されたプロを目指す人のためのRuby入門、通称チェリー本の第2版を著者の伊藤淳一@jnchitoさんからご恵送賜りました (ありがとうございます!)
遅くなりましたが、本書を読んだ感想を書かせていただきます。

まえがき: チェリー本とわたし

チェリー本といえば、第1版が発売されたのはちょうど4年前の2017年11月25日でした。
当時のわたしはプログラミングというものを学び始め、自分にとっての初めてのプログラミング言語であったRubyにも出会ったばかり。
タイミングの良いことにチェリー本の発売日とまったく同じ日、当時住んでいた福岡にて、地域RubyコミュニティFukuoka.rb主催の地域Ruby会議である福岡Ruby会議02が開催されていました。
右も左も分からない状態で福岡Ruby会議02に参加したわたしは、わからないなりにこのカンファレンスの空気に気持ちを昂らせ、そして昂った気持ちのその勢いで帰り道にチェリー本を購入したのでした。

そうして出会ったチェリー本をまずは一読し、まだまだ理解には及ばなかったために後日再読し、更にプログラマに転職してからもTama.rbチェリー本輪読会でも今一度再読し、あと別の機会にももう一回読み直した記憶があるような…もちろん通読するばかりでなく、働き始めてしばらくの間は辞書代わりに手元に置いて、必要な局面が訪れるたびに開いていました。

チェリー本を読んでプロ (グラマ) になった人は沢山いると思います。わたしもそのうちの一人です。
そうやってお世話になってきたチェリー本の第2版を、今度は職業Rubyプログラマの立場で読むことができ、とても嬉しく思っています。

改めてありがとうございます! > 伊藤さん

チェリー本はどんな本?

…についてはすでに公式・非公式問わず、たくさんの紹介があります。

また、第1版との比較については、@aim2bpgさんのブログにて (伊藤さんも驚かれるほど) 詳細に解説されていました。

aim2bpg.com

感想

さすがに最近はチェリー本にお世話になる機会が減っていたので久々に通読したことになります。

本文中で紹介されている構文やメソッドのうち多くは普段から馴染みがあるものなので、自然と以前読んでいまいちピンと来なかったところや、以前は頭に入りきらなかったところに意識が向くことになります。
そうすると、まるで復習をしているように「そうそう、これってこういうこと!」と現在の自分の理解を確かめる場面があったり、あるいは全くの新しい発見に出くわす場面があったり、4年前とはまた違う新鮮さを覚えながら読み進めることができました。

例えば、「2.12.3 式(Expression)と文(Statement)」(P74)

ここでは式と文の違いを「値を返し、結果を変数に代入できるものが式」「値を返さず、変数に代入しようとすると構文エラーになるものが文」と定義します。 このような分類で指揮と文を区別すると、Rubyのif文やメソッド定義は文ではなく、式になっています。なぜならif文やメソッド定義が値を返すからです。

について、「メソッド定義が値を返す」ことについては今回読んでいて初めてちゃんと認識しました。
(REPL環境でメソッドを定義するとメソッド名がシンボルで返ってくるので、言われてみればそれはそう…!という感じなのですが)

解説そのものが第1版よりもさらに丁寧にわかりやすいよう改善されていることも大きいと思います。
特に以前読んだ時に難しく感じた第10章「yieldとProcを理解する」は、処理順が図示されていたり、そもそものyieldやProcの用途について踏み込んだコラムが追加されており、これなら初めて読む人でもyieldとProcの概要を掴むことができるのではないかなと思いました。

もちろん復習だけでなく、新しい解説も追加されています。

第11章「パターンマッチを理解する」では、パターンマッチの作者である@k_tsjさんをして「世界トップレベルと言っていい」と評されるほど丁寧な、具体例を交えた解説がなされています。

自分自身ではまだ本格的にパターンマッチを活用する機会を得ていないのですが、サンプルコードを動かし演習をするだけでもその気持ち良さを試すことができます。
使いどころがあればぜひ使いたい!…し、その機会が来たときにはまたもやチェリー本を傍らに実装を検討することになりそうな気がしています。

新機能といえば他にも第12章「Rubyデバッグ技法を身につける」では、もうすぐリリースのRuby3.1から導入される新しいデバッガ debug.gem の基本的な使い方が紹介されています。
debug.gemは非常に多機能で、公式のREADME.mdもとてもとても充実しているのですが、とりあえずチェリー本で紹介されている機能だけでも頭に入れておけば迷わずスッと使い始めることができそうです。

更に第13章「Rubyに関するその他のトピック」の中には、typeprofsteepの概要と使い方について、型入門者向けの絶妙な塩梅での解説が含まれていたりします。

個人的にチェリー本の一番の特徴は、その網羅性と実用性にあると思います。
だからこそ、第1版を読んでいた当時から時間をおいて今、改めて第2版を読むことによって、この4年間の総復習と新機能についての実務を前提にしたキャッチアップをすることができるのではないかなと感じました。

最後に

Rubyプログラマとして働いている今、チェリー本はプロを目指す人々のためだけの本ではないなあ、と思っています。
チェリー本 第2版を読み、自分のこれまでを振り返り、今現在とこれから将来のRubyとのお付き合いを考える時間を持つことができました。
特にわたしと同じく第1版を読んでプロ (グラマ) になった皆さん、年末年始休暇のお供にいかがでしょう?

Ruby Advent Calendar 2021: パケットキャプチャ入門 with dRuby

訂正とお詫び (2022/3/5)

この記事の最後に「WiresharkdRubyに対応していないためキャプチャできなかった」と結論づけているのですが、筆者の不見識でWiresharkdRuby用のディセクタがビルトインされていることに気づいていませんでした。
申し訳ありません。

以下のように設定するとdRubyパケットをキャプチャすることが可能です。

Wireshark > Preferences > Protocols > DRb

ポート番号を指定する

f:id:shioimm:20220305154156p:plain

以下は元の記事 (未編集) です↓


Ruby Advent Calendar 2021 17日目の記事です。
昨日は@okuramasafumiさんでした。


この記事は

2台の機器 (MacBookThinkPad) がお互いに通信を行うような
dRubyスクリプトを書き、その実際の通信の様子をWiresharkで眺める

という小さな実験を行った際の記録です。

きっかけ

最近Wiresharkに入門したのですが、それと同時にdRubyにも興味が湧いて勉強していました。
ご存知dRubyは、ネットワーク越しにRubyオブジェクトを操作することができるフレームワークです。
HTTP通信と同じく、dRubyスクリプトを実行するときに機器間で実際に発生する通信は通常、TCP/IPプロトコルレイヤによって隠蔽されています
そこで機器間で送受信されたdRubyスクリプトが実際にパケットとして、あるいはアプリケーションデータ (※) としてネットワーク上をどんな風に流れているのか、その様子を見てみたいと思い立ち、今回の実験に至りました。

※ 実際にキャプチャした結果衝撃の事実に直面することになりました。むしろなぜこの時点で気づかなかった…

以下記事の内容に誤りなど技術的指摘がありましたら、お手数ですが教えてください。


動作環境

2台のPCのグローバルIPアドレスを調べたところ、

となっていました。

2台の機器は以下のように疎通確認済みです。

# ThinkPad
$ ping6 2400: ... :4808 -c 3
PING6(56=40+8+8 bytes) 2400: ... :439c --> 2400: ... :4808
16bytes from 2400: ... :439c, icmp_seq=0 ttl=64 time=4.26ms
16bytes from 2400: ... :439c, icmp_seq=1 ttl=64 time=4.86ms
16bytes from 2400: ... :439c, icmp_seq=2 ttl=64 time=4.25ms

--- 2400: ... :439c439c ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
# MacBook
$ ping6 2400: ... :439c -c 3
PING6(56=40+8+8 bytes) 2400: ... :4808--> 2400: ... :439c
16bytes from 2400: ... :4808, icmp_seq=0 hlim=64 time=94.183ms
16bytes from 2400: ... :4808, icmp_seq=1 hlim=64 time=116.538ms
16bytes from 2400: ... :4808, icmp_seq=2 hlim=64 time=34.263ms

--- 2400: ... :4808 ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss

MacからThinkPadへの通信にやたら時間がかかっていますが、弊環境だと大体いつもThinkPadの方が通信速度が優秀なのです…

改めてdRubyについて

皆さんご存知、Rubyのための分散オブジェクトシステムです。

分散オブジェクト技術 【distributed object technology】
library drb

dRubyによって、Rubyオブジェクトをプロセスやネットワークを超えて操作することが可能になります。

作者である咳さんご自身がdRubyの基本的な使い方について紹介されているRubyKaigi 2016の登壇動画はこちらです。

youtu.be

簡単な動作例を以下に示します。

ターミナルを二つ開いてそれぞれirbを起動し、drbライブラリをrequireします。

# ターミナル1 
$ irb --simple-prompt
>> require 'drb'
=> true
# ターミナル2
$ irb --simple-prompt
>> require 'drb'
=> true

続いてターミナル1でFooクラスとインスタンスメソッドfromを定義します。

# ターミナル1
?> class Foo
?>   def from
?>     "I'm from terminal 1!"
?>   end
>> end
=> :from

続いてターミナル1でDRb.start_serviceを実行すると、サーバープロセスを起動することができます。
このとき、DRb.start_serviceの第一引数にクライアントがアクセスするためのURI、第二引数にFooオブジェクトを渡します。
第二引数に渡したFooオブジェクトは他のプロセスから操作可能なオブジェクトとして公開されます。

# ターミナル1 
>> foo = Foo.new
>> puts foo
#<Foo:0x00007f81149b7cf0>
>> DRb.start_service("druby://localhost:8080", foo) # ローカルホストのポート番号8080で待ち受ける

これで、ターミナル2からターミナル1のFooオブジェクトに対してメソッド呼び出しができるようになります。
ターミナル2からFooオブジェクトに対してメソッド呼び出しするためには、まずターミナル2でDRbObject.new_with_uriを実行します。 このとき、引数にターミナル1のサーバープロセスが待ち受けているURIを指定します。

# ターミナル2
>> foo = DRbObject.new_with_uri('druby://localhost:8080')
>> puts foo
#<Foo:0x00007f81149b7cf0>

こうすることによってターミナル2からターミナル1のFooオブジェクトの複製であるオブジェクト (※) を取得することができます。

※ この辺り難しいので詳しくは後述のdRuby Bookを参照

ターミナル2から変数fooに格納されたオブジェクトに対してfromメソッドを実行すると…

# ターミナル2
>> foo.from
=> "I'm from terminal 1!"

ターミナル2にfromメソッドの返り値が表示されました!
ターミナル2から、ターミナル1で定義したFoo#fromのメソッド呼び出しに成功したということです。

逆に、ターミナル1からターミナル2にあるオブジェクトへの操作も試してみましょう。

# ターミナル2
?> class Bar
?>   def from
?>     "I'm from terminal 2!"
?>   end
>> end
=> :from
>> DRb.start_service("druby://localhost:8081", Bar.new) # ローカルホストのポート番号8081で待ち受ける
# ターミナル1
bar = DRbObject.new_with_uri('druby://localhost:8081')
bar.from
=> "I'm from terminal 2!"

こちらももちろん成功します。楽しいですね!

ちなみにBar#fromの内容を"I'm from terminal 2!"ではなくputs "I'm from terminal 2!"にしたりすると、ターミナル2に"I'm from terminal 2!"が表示され (ターミナル2の標準出力はターミナル2のままなので) 、ターミナル1にはnilが返ります (putsの返り値はnilなので) 。

他にもdRubyは様々な特徴を備えています。
詳しくはdRubyによる分散・Webプログラミング(あるいは英語版・無料のThe dRuby Book)、そして「令和のdRuby Book」といった趣きのn月刊ラムダノート Vol.2, No.1(2020)の特集「#2 dRubyで楽しむ分散オブジェクト」もおすすめです。

ThinkPadMacBook、それぞれの機器で実行するdRubyスクリプト

今回の実験では、次のようなプログラムを動作させることにしました。

  1. ThinkPadはサーバープロセスをポート番号8080で起動し、MacBookからアクセスすることができる空のKVS { } (…という名の空ハッシュ)を公開する
  2. MacBookはサーバープロセスをポート番号8081で起動し、ThinkPadからアクセスできるようにしておく
  3. MacBookThinkPadの公開しているKVS { } を取得する
  4. MacBookが取得したKVSにレコード{ "greeting" => "Hello from MacBook" }を追加する
  5. ThinkPadは自身が公開しているKVSにレコードが追加されたことを検知し、自身の標準出力にログを出力する
  6. MacBookが再びKVSにレコード{ "stdout" => $stdout }を追加する
  7. ThinkPadは再び自身が公開しているKVSにレコードが追加されたことを検知し、自身の標準出力にログを出力する
  8. ThinkPadはKVSに追加されたレコードがttyに結合している場合、結合先にメッセージ"Hello from ThinkPad"を出力する

f:id:shioimm:20211114215214p:plain

プログラムは次のようになります。

https://github.com/shioimm/til/tree/master/activities/learning_network_with_drbgithub.com

# thinkpad.rb

require 'drb'

kvs = {}

# 新たに追加されたレコードを検証するために使用する
last_kvs = {}

# サーバープロセスをポート番号8080で起動して空のKVSを公開
DRb.start_service("druby://#{ENV['LOCAL_HOST_ADDRESS']}:8080", kvs)
puts "Start server process on #{DRb.uri}"

loop do
  if kvs.size > last_kvs.size
    puts "New record has been added:\n#{kvs}"

    new_values = (kvs.values - last_kvs.values)
    new_stdouts = new_values.select { |value| value.respond_to?(:tty?) && value.tty? }

    unless new_stdouts.empty?
      # 追加されたレコードがttyに結合している場合は"Hello from ThinkPad"を出力
      puts "Greet to client: 'Hello from ThinkPad'"
      new_stdouts.each { |new_stdout| new_stdout.puts "Hello from ThinkPad" }
    end

    last_kvs = kvs.dup
  end

  sleep 1
end
# macbook.rb

require "drb"

# サーバープロセスをポート番号8081で起動
DRb.start_service("druby://#{ENV['LOCAL_HOST_ADDRESS']}:8081")
puts "Start server process on #{DRb.uri}"

# ThinkPadが公開しているKVSを取得
uri = "druby://#{ENV["REMOTE_HOST_ADDRESS"]}:8080"
kvs = DRbObject.new_with_uri(uri)

puts "[LOG] uri = #{uri}"
puts "[LOG] kvs = DRbObject.new_with_uri(uri)"
puts "[LOG] kvs:\n#{kvs}"

# KVSにレコード { kvs["greeting"] => "Hello from MacBook" } を追加
kvs["greeting"] = "Hello from MacBook"

puts "[LOG] kvs['greeting'] = 'Hello from MacBook'"
puts "[LOG] kvs:\n#{kvs}"

sleep 1

# KVSにレコード { kvs["stdout"] => $stdout } を追加
# この$stdoutはMacBook自身の標準出力
kvs["stdout"] = $stdout

puts "[LOG] kvs['stdout'] = $stdout"
puts "[LOG] kvs:\n#{kvs}"
puts "[LOG] sleep"; sleep

あらかじめ環境変数LOCAL_HOST_ADDRESSREMOTE_HOST_ADDRESSを各機器にセットしておきました。
ThinkPadLOCAL_HOST_ADDRESSThinkPadIPアドレス (末尾439c)、REMOTE_HOST_ADDRESSMacBookIPアドレス (末尾4808) です。
MacBookにはその逆になります。

これらのプログラムをそれぞれMacBookThinkPadに置き、それぞれ実行すると以下のようになります。

# ThinkPad
$ ruby thinkpad.rb
Start server process on druby://2400: ... :439c:8080
# MacBook
$ ruby macbook.rb
Start server process on druby://2400: ... :4808:8081
[LOG] uri = druby://2400: ... :439c:8080
[LOG] kvs = DRbObject.new_with_uri(uri)
[LOG] kvs:
{}
[LOG] kvs['greeting'] = 'Hello from MacBook'
[LOG] kvs:
{"greeting"=>"Hello from MacBook"}
# ThinkPad
...
New record has been added:
{"greeting"=>"Hello from MacBook"}
# MacBook
...
[LOG] kvs['stdout'] = $stdout
[LOG] kvs:
{"greeting"=>"Hello from MacBook", "stdout"=>#<DRb::DRbObject:0x00007fa55c8a57b0 @uri="druby://2400: ... :4808:8081", @ref=80>}
[LOG] sleep
# ThinkPad
...
New record has been added:
{"greeting"=>"Hello from MacBook", "stdout"=>#<DRb::DRbObject:0x00007fa55c8a57b0 @uri="druby://2400: ... :4808:8081", @ref=80>}
# MacBook
...
Hello from ThinkPad

無事にMacBookからThinkpadへ、ThinkPadからMacBookへ、お互い通信を行うことができました!

実際の通信の様子をWiresharkでキャプチャしてみる

上記のやりとりをキャプチャします。

WiresharkこちらからMacBookへダウンロードし、インストール済みです。
(ThinkPad(Ubuntu)にもaptを使ってインストールしたのですが、今回はクライアントであるMacBookでキャプチャしたファイルのみを確認します)

早速Wiresharkを開いてキャプチャを開始すると、次のような通信の様子が表示されました。

f:id:shioimm:20211124222737p:plain

この状態で、それぞれの機器でプログラムを実行します。

# ThinkPad

$ ruby thinkpad.rb
Start server process on druby://2400: ... :439c:8080
New record has been added:
{"greeting"=>"Hello from MacBook"}
New record has been added:
{"greeting"=>"Hello from MacBook", "stdout"=>#<DRb::DRbObject:0x00007fa55c8a57b0 @uri="druby://2400: ... :4808:8081", @ref=80>}
# MacBook
$ ruby macbook.rb
Start server process on druby://2400: ... :4808:8081
[LOG] uri = druby://2400: ... :439c:8080
[LOG] kvs = DRbObject.new_with_uri(uri)
[LOG] kvs:
{}
[LOG] kvs['greeting'] = 'Hello from MacBook'
[LOG] kvs:
{"greeting"=>"Hello from MacBook"}
[LOG] kvs['stdout'] = $stdout
[LOG] kvs:
{"greeting"=>"Hello from MacBook", "stdout"=>#<DRb::DRbObject:0x00007fa55c8a57b0 @uri="druby://2400: ... :4808:8081", @ref=80>}
[LOG] sleep
Hello from ThinkPad

プログラムの実行に成功したため、一旦ここでキャプチャを止めてファイルとして保存しました。

f:id:shioimm:20211124223713p:plain

保存したファイルを開き、今回実験した内容を通信に絞り込むため次のような条件でフィルタをかけました。

tcp.port == 8080 || tcp.port == 8081
  • 8080: ThinkPadのサーバープロセスのポート番号
  • 8081: MacBookのサーバープロセスのポート番号

すると…

f:id:shioimm:20211124225719p:plain

(上から下まで全部TCP)

(dRubyスクリプトが含まれているはずの) アプリケーションデータがキャプチャできていない…!?

…と、ここまで来て気づいたのですがWiresharkがキャプチャできるのはWireshark自身がサポートしているアプリケーションプロトコルのみなのでした。
残念ながらその中にdRubyは含まれていないため、キャプチャファイルではトランスポート層でやりとりしたTCPパケットの情報のみが表示されています。それはそう…!!

せっかくなので、dRubyならではのちょっと特徴的なパケットの様子を見てみたいと思います。

f:id:shioimm:20211124230138p:plain

先ほど実験用プログラムの中で、ThinkPadのサーバープロセスのポート番号を8080、MacBookのサーバープロセスのポート番号を8081としました。
通信の始まりであるこの行では、ThinkPadの8080番に対して、MacBookの55094番から[SYN]を送るところから通信が始まっています。
この時、MacBookはクライアントとしてパケットを送信しているため、自身のサーバーのプロセスの8081番ではなくてエフェメラルポートである55094番を使用しています。
2行目ではThinkPadの8080番からMacBookの55094番に対して[ACK]が返っていることが確認できます。

この後順調に通信が進んでいくのですが、190行目で突然シーケンス番号0の新しい通信が開始されます。

f:id:shioimm:20211124230324p:plain

見切れていますが送信元のIPアドレスの末尾が439c、宛先のIPアドレスの末尾が4808でポート番号が8081になっているので、これはThinkPadからMacBookのサーバーポート宛の通信であることがわかります。
(ThinkPadからMacBook"Hello from ThinkPad!"と送信している分です)
今度はThinkPadがクライアントになっているので、送信元のポート番号として38272という番号が割り当てられています。

最後に、それぞれの端末から通信をCtrl+Cで切断した部分がこちらです。

f:id:shioimm:20211124230610p:plain

シンプルなサーバー・クライアントシステムの場合、お互いが[FIN, ACK]と[ACK]を送り合っておしまいになると思うのですが、今回サーバープロセスとクライアントプロセスが2つずつあるため、通常の2倍の[FIN, ACK]と[ACK]が飛び交っていてちょっと面白いです。

まとめ

今回の実験の内容自体はdRuby的にもWireshark的にも最初の一歩を踏んだ程度のものではあるのですが、個人的にはパケットをキャプチャしてまじまじ眺める経験そのものが初めてだったためとても勉強になりました。
残念ながら送受信しているdRubyスクリプトそのものをアプリケーションデータとして確認することはできませんでした…が、実際にネットワークを超えて行くTCPパケットとしてのdRubyの姿を眺めることができて感動しました。
WiresharkdRubyもまだまだ奥が深そうなので、引き続き楽しんでいきたいと思います。


以上、「Ruby Advent Calendar 2021: パケットキャプチャ入門 with dRuby」でした。

明日は@yancyaさんです。
それでは皆さん楽しいクリスマスをお過ごしください🎄🍰

Rubyist近況 Advent Calendar 2021: 近況報告 + 今年一番お世話になったメソッドにお礼を言いたい

Rubyist近況 Advent Calendar 2021 12日目の記事です。
昨日は@miyohideさんのRubyもJavaも楽しく学ぶ でした。


近況ということで2021年を振り返ってみたいと思います。

仕事

現職で働き始めて3年が経ちました。
変わらず英語塾で学習管理システムのバックエンド開発を担当しています。

昨年 (2020年) 達人プログラマーエクストリームプログラミングClean Agileと立て続けに素晴らしい書籍を読んだため、この経験を仕事で活かせないかな〜と思い今年からカリキュラムチームの定例ミーティングに参加させてもらうようになりました。
より現場に近いカリキュラムチームと一緒に仕事をするようになったことで、(今更ですが) システムだけではなくお客様に提供するサービス全体を自分 (たち) の作るプロダクトとして考えることができるようになった、というのが自分にとっての今年一番大きな進歩ではなかったかなと振り返っています。
開発の進め方にも自分の中に軸のようなものが生まれたように思います。

また、ちょうど一年くらい前に開発チームメンバーが3人増えて賑やかになりました。
一方ご時世柄もあり全員リモート勤務なので、お互いが何をやっているのかわからない状況が発生しないよう、メンバーや上司の発案で毎日雑談タイムを設けたり、毎週技術書の読書会をしたり、週次で皆の動きを振り返ったりしています。
ただコミュニケーションの方法は人それぞれだし、そもそも自分自身もあまり得意な方ではないので、今より更に良くできる余地はありそう。
とはいえ、一緒に働く人たちと上司がいつも本当にniceなおかげで楽しく仕事しています。
前述のカリキュラムチームも含め、周りの人々からは引き続き学ぶことばかりです。

今現在はこれからのサービス展開に向け、これまで経験した中でも一番大がかりな仕事の真っ最中です。
これはまだしばらくかかりそうなので、来年も引き続きがんばります。

仕事以外

憧れのRubyKaigiに登壇しました!!!!
というのが今年一番大きな出来事です。

coe401.hatenablog.com

詳しくは↑の記事に書いたので、ここではそれ以外のことを…

  • 3月、Fukuoka.rb 200回 LT大会 (#202)で喋りました
  • 2~4月くらい、プログラミングElixirをお供にElixirの勉強をしていましたが、わたしにはまだ早すぎた感がありました
    • ただ、おかげでRubyのパターンマッチにちょっと親近感が湧きました
    • なお、プログラミングElixirはまえがきとあとがきも最高でした…
  • 4月、1月から読み始めたLinuxプログラミングインターフェース(1604ページ)を読み終えました
    • これを読んで何かを作ろうという段階ではないのですが、困ったらとりあえずこの本、というお守り代わりにしようと思っています
    • 2021年の目標は「LPIを読む」だったので達成できて嬉しいです
  • しばらく趣味の喫茶店を控え目にしていたのですが4月、感染状況の様子を伺いつつ銀座のカフェ・ド・ランブル行きました
    • Asakusa.rbでおすすめしてもらいました
  • 5月、キッズドアのマンスリーサポーターになりました
    • わたしは自分自身が子育てに関わっていないので、自分の周りの親御さんたちの奮闘を (主にTwitterで) 陰ながら応援するくらいしかできないのですが、その分世の中のお子さんたちへ、わずかながらでも自分にできることができたらいいなと密かに思っています
  • 5~6月、マスタリングTCP/IP 入門編を読み直したら学びしかなくてびっくりしました
    • 今年は一年通じてずっとTCP/IPプロトコルスタックのことを考えていましたが、一方で全然専門的な領域に入っていくまでに至っておらず、その点については若干焦りもあったりしています
  • 6~9月、RubyKaigiの準備で記憶がない…
  • 9月以降はRubyKaigiの余韻にひたりつつdRubyに入門していました
  • 10月、2019年から運営として関わっていたTama.rbが最終回を迎えました
  • さらに10月、Kaigi on Rails 2021に一参加者として参加しました (重言)
    • 今年の貴重なRuby (Rails) 関連のイベントだったので、楽しくお話を聞いたり登壇される方の応援をしたり懇親したりしました
  • 10月以降、感染状況が少し落ち着いているので、今のうちということで週末に趣味の喫茶店に出かけたりしています
    • 出かけた先の街をぶらぶら散歩するのが最近の趣味です。川にも行きました
    • 気づいたら上京して3年を超えていましたが、半分自粛生活だったので全然実感がなく、いまだにどこに行ってもおのぼりさん状態です
  • 11月、大江戸Ruby会議09 出前Editionにこれまだ一参加者として参加しました (重言2)
    • 最っっっ高のイベントでしたね
    • Asakusa.rb 第634回 (キリ番) ミートアップ開催おめでとうございます
  • 12月、Ruby3.1リリースを前に話題のRuby関連技術書(研鑽Rubyプログラミング β版プロを目指す人のためのRuby入門[改訂2版])が2冊も出版され、それぞれ楽しく読んでいます
  • 今年いつの間にかFukuoka.rbのconnpassページの管理者に追加してもらっていました
    • Fukuoka.rb 第234回 (キリ番) ミートアップ開催おめでとうございます
  • 今年 (も) 上記した本含めてたくさん本を読みました。そのうち多くの本を周りのRubyistの人々におすすめしていただきました
    • その節は本当にありがとうございました
    • 特に@udzuraさんと@takkanmさん!!
      • 他にも「この本はxxさんが良い本と仰っていたな〜」という記憶を頼りに本当は一冊一冊紹介したいくらいなのですが、さすがに書ききれなくなってしまうので控えます
  • 今年も相変わらずAsakusa.rbとFukuoka.rbによくいました。他の地域Rubyコミュニティミートアップにもたまにいます

ということであっという間に思えて実は色々あった今年も相変わらずRubyでお仕事をし、Rubyコミュニティにいて、Rubyが好きです。
RubyRubyistの人々には2021年もたくさんお世話になりました。
プログラマとして過ごす生活の中で自分が本当に好きだなと思える言語や言語コミュニティがあるというのは幸せなことだなと思います。

そんな訳でせっかくなので、今年自分が書いたRubyプログラムの中で一番お世話になったメソッドにお礼を言うことにしました。

といっても、業務も含めて実際に書いたコード全てを集計して一番お世話になったメソッドを見つけるのはさすがに大変です。
わたしは毎日「その日新しく知ったこと」をtilというリポジトリにまとめているのですが、この中には練習のために書いてみたコードや写経したコード、イベントのために書いたコードなども入っています。
なので今回はこのtilリポジトリ内のコードを対象に集計することしました。

github.com

要件は次の通りです。

  • 今年初め(1月1日)からこの日記を書いた12月3日までの間に更新されたファイルを対象に、各ファイル内で実行されているメソッドごとの実行回数を集計する
  • その中でも特にお世話になった (リポジトリの中で実行回数が多かった) メソッドを20個、降順に取得する
  • 明示的にソースコード中で呼び出したメソッドだけではなく、Ruby自身がコードの裏側で実行しているメソッドも対象に含める

ただし、そのままでは実行が難しかったものがあったのでいくつか条件をつけました。

  • 無限ループが含まれるコードがあるため、実行時間が5秒以上かかったファイルは例外を上げて次の処理に移る
  • 特定の条件付きで実行することを想定して書かれているコードがあるため、実行時に例外が発生した場合は例外を上げて次の処理に移る

集計のために書いたスクリプトは以下の通りです。

til/counter.rb at master · shioimm/til · GitHub

require 'timeout'

files   = ARGV
counter = Hash.new { 0 }
trace   = TracePoint.new(:call, :c_call) { |tp|
  counter["#{tp.method_id} (#{tp.defined_class})"] += 1
}
$stdout = File.open(File::NULL, 'w') # ファイル実行中の出力を抑制する

files.each do |file|
  f = File.open(file, 'r')

  begin
    Timeout.timeout(5) {
      trace.enable { eval f.read }
    }
  rescue StandardError, LoadError
  end

  f.close
end

$stdout = STDOUT # 出力を元に戻す

most_used_methods_20 = counter.sort_by { |_method, count| count }.reverse.first(20)

pp most_used_methods_20.to_h

(もっと良い方法があるかもしれないので、識者の方に突っ込みをいただきたいです…)

取得したメソッドのうち、一番お世話になったメソッドには次の通りお礼を言います。

# ...
puts "#{most_used_methods_20[0][0]}、本年は大変お世話になりました。\n来年もよろしくお願いします。"

早速実行してみました。

$ find ~/til -name *.rb -newermt '20210101' | xargs ruby ~/til/activities/20211212_rubyist_advent_calender/counter.rb

すると、次のように結果が出ました。

{"+ (Integer)"=>3131838,
 "up (Counter)"=>40000,
 "synchronize (Thread::Mutex)"=>21471,
 "method_added (Module)"=>3054,
 "-@ (String)"=>2560,
 "initialize (Thread)"=>2046,
 "new (#<Class:Thread>)"=>2046,
 "sleep (Kernel)"=>1775,
 "wait (Thread::ConditionVariable)"=>1767,
 "sleep (Thread::Mutex)"=>1767,
 "data (Gem::StubSpecification)"=>1468,
 "file? (#<Class:File>)"=>1372,
 "% (String)"=>1316,
 "chr (Integer)"=>1312,
 "+ (String)"=>1260,
 "to_s (Symbol)"=>1182,
 "rand (Kernel)"=>1068,
 "write (IO)"=>970,
 "=== (Module)"=>895,
 "current (#<Class:Thread>)"=>871}

ということで、2021年わたしが一番お世話になったメソッドはIntegerの+でした!
おそらくこのファイルの実行によって数が増えたものと思われます。
https://github.com/shioimm/til/blob/master/practices/ruby/concurrency/benchmarks/20210131_bench.rb

その他のメソッドについても、今年前半に勉強していたスレッドプログラミング関連のものが多そうです。

ベンチマークスクリプトの中で使用していたメソッドなのでだいぶチート感がありますが、お世話になったことに変わりはないので+には早速お礼を言いました。

+ (Integer)、本年は大変お世話になりました。
来年もよろしくお願いします。

以上、「Rubyist近況 Advent Calendar 2021: 近況報告 + 今年一番お世話になったメソッドにお礼を言いたい」でした。
明日は@s01さんです。

それでは皆さん楽しいクリスマスをお過ごしください🎄🍰