RubyKaigi 2022 Kotlin愛好家たまにRubyistによるセッションレポート Day3
株式会社TOKIUMの坂上(HN: にしこりさぶろ〜)です!この記事では、9月8日(木)-10日(土)の3日間に渡り開催されたRubyKaigi 2022にて、聴講したセッションの中でも印象に残ったモノをいくつか紹介していきます。
仕事では、AndroidエンジニアとしてKotlinのコードを書いている時間が最も長く、コミュニティ活動もKotlin開発者として参加することが多いため、「特定の企業が開発し、OSS化された」「静的型付け言語」の世界を主戦場とする開発者の目線からレポートを残そうと思います。
Day3で印象に残ったセッションは、以下の3つです
- RBS generation framework using Rack architecture
- Let's collect type info during Ruby running and automaticall
- String Meets Encoding
RBS generation framework using Rack architecture
RBSファイルを自動生成するツール「orthoses」を開発しているYuki Kuriharaさんの発表です。
アジェンダ
- RBSファイルの自動生成ツール「orthoses」の紹介
- ツール開発のモチベーション
- Rubyプロジェクトへの型の導入に対する課題
- アーキテクチャ、および実装の紹介
- Rackアーキテクチャの紹介
- TracePointを利用したRBSファイルの自動生成ロジックの紹介
解説 #1: ツール開発のモチベーション
Rubyプロジェクトに型情報を追加するRBSですが、Ruby特有の様々な課題が山積しており、エコシステムがなかなか育たない現状にあります。膨大な量の型定義・ファイルが必要とされますし、それらは正確でなければならず、その上Gem間の依存関係も解決しなければ型を決定できないこともあることから、拡張性や柔軟性も求められます。
Rubyによるプログラミングで開発者に大きな幸福をもたらすため、型をどこでも扱うことができ、ありふれた状態にしたい。これを達成するためのアプローチとして、型ファイルを自動で生成できるツールを考案しました。
解説 #2: Rackアーキテクチャでの実装
orthosesは、Ruby製WebアプリケーションフレームワークであるRackのアーキテクチャを取り入れています。型定義の自動生成に必要な機能をMiddlewareにまとめ、use Middleware
の書式で必要なだけ取り込めるようなアーキテクチャとしています。ファイルの生成はCLIではなく、Rakeタスクとして定義することも大きな特徴です。
既に定数・Mixin・Attributes( attr_accessor
/attr_writer
/attr_reader
)等、Rubyの主要な言語機能への型定義を提供するMiddlewareは用意されており、また型定義の生成対象としてライブラリ・アプリケーションいずれも指定することが可能です。
感想
RBSファイルの自動生成に関するセッションでしたが、ライブラリ・アプリケーションのどちらに対しても定義を生成できるという点に大きなインパクトを感じました。また、Rakeタスクとして自動生成スクリプトを用意し、必要なMiddlewareを必要なだけ読み込み、不足していれば実装する設計としていることで、ライブラリのアップデートにも追従しやすい柔軟性を備えている点も非常に勉強になりました。
実装解説やサンプルコードから、Rubyの言語仕様をフルに活かして開発されていることが伝わり、じっくりコードリーディングをしたい欲求に駆られたことを覚えています☺️ 休日に読み進めて、自分でも自動生成スクリプトを何か1つ書いてみようかと思います。
Let's collect type info during Ruby running and automaticall
スライド: https://www.docswell.com/s/pink_bangbi/5MPPE5-2022-09-10-092906
連続して、型定義に関連するセッションです。こちらもorthosesと同じく、Rubyの実行時の処理をトレースし、その情報を元に型定義を自動生成するアプローチを採用しています。
アジェンダ
- Rubyの実行時の処理を元にRBSを生成するツールを実装した話
- RBSの自動生成に対するモチベーション
- 実装の詳細解説
- TracePointを使ったメソッドの引数・返り値の推論
- オプションの機能
- 型の自動生成を実装する上で考えたこと
解説 #1: RBSの自動生成に対するモチベーション
モチベーションの出発点は、「型情報は書きたくないが型の恩恵は受けたい」という欲求でした。より詳しく説明すると、Rubyのコードを静的に解析してRBSを生成するアプローチは、既にTypeProfで行われており、それとは別のアプローチでRBSを生成したいという気持ちがありました。
解説 #2: 実装したツールの詳細解説
実際に実装したコマンドラインツール「rbs-dynamic」は、TracePointを利用しRubyの実行時の情報を収集、それらを元にRBSの自動生成を実現しています。定数・クラスメソッド・ブロックといった基本的な機能に対する型はもちろんのこと、「特定のメソッドを持つクラス」であることを表すインターフェース型の生成も可能です。
また、コマンド実行時にオプションをつけることによって、メソッドの呼び出し元の場所と引数・返り値の型をコメントで表示できるような機能も実装しています。これにより、呼び出し元によって型定義が変化するケースにおいても、処理を追いやすい状態を保つことができます。
このように、rbs-dynamicでは「動いているコードを正」とする前提の元で型を定義するアプローチで自動生成を実装しています。ですが、これは型が先に定義される一般的な静的型付け言語とは真逆の状態であり、意図しない型が入ってしまう場合も正として扱われてしまう課題もあります。
感想
RBSの自動生成に対するアプローチとして、orthosesとかなり近い実装でしたが、「ライブラリとしての使いやすさ・柔軟性・拡張性」を追求していたorthosesとは異なり、「RBSを今後どのように扱っていくべきかの議論のきっかけ」を生み出そうとしていたことが印象的でした。
僕は普段、型システムが当たり前のように存在するKotlinでのプログラミングに多くの時間を割いていることから、「型をどのように扱うべきか」という発想や議論にそもそも思い至ることがなく、この発表で新しい世界に触れられた気がしました。大規模なユースケースでの利用が増加し、導入の要求が高まった型についても、Ruby本来の良さを活かしながらじっくり議論をしつつ取り入れていこうとする姿勢を感じ、Rubyist達がコミュニティの存在を大切していることを改めて実感しました。
String Meets Encoding
自己紹介で「文字コードが好き」と語ったMari Imaizumiさんによる、メソッドの実行速度の改善についてのセッションです。
アジェンダ
- CRubyの
String#split
メソッドを高速化させたPRでの調査の話 -
String#split
メソッドのCの実装の調査手順の紹介
CSV.read
のパフォーマンス分析
解説 #1: 昨年のRubyKaigiでの発表「Dive into Encoding」を終えた後、TwitterでのツイートをきっかけにCSV.read
メソッドのパフォーマンス分析へのモチベーションが湧いたMari Imaizumiさん。試しにKEN_ALL.CSV
(=日本の全ての郵便番号情報が格納されたCSV)を読み込ませたところ、ファイルサイズの割には重そうなことに気づきました。
Rubyのプロファイリングツールである「stackprof」を利用し、分析したところ、String#split
がメソッドの実行回数全体の29%を占めている模様。このメソッドのパフォーマンスを改善できれば、CSV.read
の読み込み速度が改善できそうです。
String#split
メソッドのC実装の深掘り調査
解説 #2: 今度はLinuxコマンドのperfを利用し、String#split
の実行すると、ボトルネックになっていそうなCのメソッドをいくつか探し出すことができました。
目星をつけたCのメソッドの処理を追っていくと、引数のチェック時に動的にエンコーディング情報を取得している箇所を発見しました。String#split
は最初に渡された文字列を分割するメソッドであるため、エンコーディングの取得は最初の一度だけで良いはず。
仮説を元に、エンコーディング情報を動的に取得する実装から引数で渡す実装に変更したところ、1.1-1.4倍ほどの速度改善を達成することができました。
- UTF-8: 1.88秒→1.31秒
- US-ASCII: 1.41秒→1.36秒
感想
上記要約ではバッサリ省きましたが、1つのメソッドの分析、およびボトルネックの特定の過程が非常に丁寧に説明されており、プログラミング言語のContributorがどのように作業を進めているのかを身をもって体験することができました。
地道な作業ではあるものの、目星をつけていきながら実装を解きほぐしていく様子は強く知的好奇心を刺激され、自分もやってみたいという感情が自然と湧いてきました🙌
3日間のカンファレンスを終えて
初めてのRubyKaigiでしたが、たった3日間でこれまで触れることのなかった新たな世界をたくさん知ることができ、非常に楽しい時間を過ごすことができたと強く感じています。
コロナ前は様々な勉強会やカンファレンスに足を運んでいたこともあり、開発者コミュニティの雰囲気に一種の”慣れ”のような感情も抱いていたのですが、フォーカスする言語・フレームワークによってこんなにも空気感が変わるとは、夢にも思っていませんでした。今回は自分としても約2年ぶりのオフラインカンファレンスということもあり、Rubyistのみなさんの熱量には驚かされ、与えられるばかりでしたが、これから少しずつでもこの3日間で得たものを返していこうと思っております!
難しいご時世の中、カンファレンスの実現に尽力いただいたすべてのみなさん、本当にありがとうございました!🙇 来年もまた参加できること、楽しみにしております!🥰
【Day1・Day2のセッションレポートはこちら】
Discussion
感想記事ありがとうございます。励みになります!
String Meets Encoding のところで
と書いてあるのですが、私がRubyのCommitterのように見えるのでContributorにしておいてもらえるとありがたいです 🙏
こちらこそ、記事を読んでいただきありがとうございます!🙇♂️
ご指摘の箇所、大変失礼いたしました!Contributorの表記に修正いたしました🙇♂️