こんにちは。
サービスエンジニアリング本部の寺田と橋野です。
こちらの記事は、RubyKaigi 2023に参加しました!<後編>です。
前編は以下からどうぞ!
tech.enigmo.co.jp
後編では、RubyKaigi2023で印象に残った講演の内容を紹介をしていきます。
1日目
Matz Keynote
Youtube: [JA][Keynote] Matz Keynote / Yukihiro "Matz" Matsumoto @yukihiro_matz - YouTube
Slide: 30 Years of Ruby - Speaker Deck
[内容]
今年でRubyは30周年を迎えました。
この講演では、「Ruby」の生みの親であるまつもとゆきひろ(Matz)氏が、Rubyの30年を時系列順に振り返っていました。
学んだ教訓や主要なイベントを含め、段階に分けて説明していました。
年代 | トピック |
---|---|
1993-02 ~ 1994-12 | 始めは一人での開発 |
1994-12 ~ 1995-12 | Alpha Release 共同開発を開始 |
1997-08 ~ 1999-11 | Ruby v1.0 リリース |
1999-11 ~ 2004-10 | 初のRubyの技術書 |
2000-10 | 初の英語のRubyの技術書 |
2001-09 | JAOO (Java And Object Oriented Language) |
2001-10 | 初めてのRubyのカンファレンス |
2004-10 ~ 2009-01 | Ruby on Rails の登場 |
2009-01~2013.02 | Ruby1.9のリリース |
2013-02 ~ 2015-11 | Ruby2.0のリリース |
2015-11 ~ 2020-02 | Ruby 3x3 |
2022 ~ | Ruby 3.0 |
それぞれ紹介したテーマからMatz氏が学んだことや教訓で締めていました。
例えば、海外の人から本を書きたいとMatz氏に連絡がきたというお話しがあり、まつもとゆきひろ氏は「この本がなかったらいまのrubyがなかっただろう」という学びを得たことをおしゃっていました。
[感想]
Matz氏の学びの中に特に興味深かったものがありました。
「いい名前を選ぶ。」という教訓です。
Rubyの名前の候補に、「Coral」や「Tish」などがあったそうです。もしかしたら、Tish Kaigiになっていたかもしれませんねとお話しされていました。 TishKaigiであると言語のカンファレンスではなく、製紙会社のカンファレンスのようにみえていたかも?と思いました。
また、実務でもさまざまな場面でいい名前を選ぶということを感じています。
例えば、メソッドの命名でも、どのような役割をもったメソッドなのかをわかりづらいというレビューを受けたり、また、役割がややこしい命名をされた変数を見たりします。
「いい名前を選ぶ。」ということは私も大切であり、大きな意味と役割をもつと思っています。みなさんも大切だと感じることが多いでしょう。
この講演に参加することによって、Rubyの30年もの歴史を一気に振り返ることができました。
知らない歴史も多く、この講演を通してさらにRubyのことが好きになりました。
The future vision of Ruby Parser
Youtube: [JA] The future vision of Ruby Parser / Yuichiro Kaneko @spikeolaf - YouTube
Slide: The future vision of Ruby Parser - Speaker Deck
[内容]
この講演では、Rubyのparser実装の話を聞くことができ、3つの課題を説明します。
以下がその問題です。
- Usability (Error-tolerant parser)
- Maintainability
- Universal Parser
Usability
今までのparserはとてもシンプルであったが、Language Server Protocol(LSP)の場合それだけでは十分ではなく、責任が増えてきています。
トークンを追加もしくは削除してリカバリーをおこなったらどうだというアイデアがあります。
Insert/Deleteのオペレーションの組み合わせをやることでプログラマが構文を考慮することなくError Recoveryが実装できた。
Error Recoveryを実装するためにLrama LALR parser generatorを実装をした。
Maintainability
メンテナビリティの解決方法について、Rubyのdo
を中心に密結合しているという根深い問題に関しても他の既存のテクニックと 組み合わせることで解決ができた。
Universal Parser
CRuby以外でもparserを使いまわしをするためにUniversal Parserが必要になってくる。
CRubyの提供する関数やマクロへの依存を"parse.y"から剥がしていくことで問題を解決していく。
[感想]
BisonをLramaに置き換え、Rubyのmasterにマージされたそうです。
これでBisonのバージョンの依存関係がなくなりましたね:yatta:
Kanekoさんは、今後LALR parserの可能性を引き出していくことをしていきたいと講演でお話しされていました。
まだまだ進化していきそうなRubyのParserをwatchをしていきたいと思います。
この講演の内容を詳しく知りたいという方は、Kanekoさんのブログに丁寧に解説されているのでおすすめです。
かねこにっき
また、parserを書いてみたいけどどこから始めればいいかわからないという方向けにRubyで電卓をつくるチュートリアルをKanekoさんが書いてくださってので、興味を持った方はこの講演と合わせて試してみましょう! github.com
Make Regexp#match much faster
Youtube: [JA] Make Regexp#match much faster / Hiroya FUJINAMI @makenowjust - YouTube
Slide: Make Regexp#match much faster - Speaker Deck
[内容]
この講演では、正規表現マッチングの実装と、Ruby 3.2.0 で実装された正規表現マッチングの最適化の詳細について説明します。
流れとしては、
ReDos を防ぐために高速化することによって防ぐことができる(メモ化による最適化)
正規表現マッチングの今後の展望
の順にお話をされていました。
Rubyの正規表現マッチングはパワフルだけど、ReDosと呼ばれる脆弱性があり、その例をスライド内で紹介していました。
しかし、正規表現マッチングの実装の改善をし、待ち時間の短縮をさせ、ReDosが起こらないようにRuby3.2からではおこなわれています。
また、正規表現の拡張的な機能などはメモ化による高速化はおこなわれていないそうです。
[感想]
ReDoSの起きてしまう理由やどのような手順で高速していったかを、ひとつひとつ丁寧に解説されていました。
しかし、Youtubeの内容を見直してみたのですが、本題であるメモ化による最適化の話のあたりが難しくまだ完璧には理解ができていません。
スライドの中に実行時間の比較があったのですが、Ruby3.2からでは時間がかなり短くなっていました。
Ruby3.2の変更を追えていなかったので、とても勉強になりました。 今後、理解していけるように正規表現について少しずつ学んでいきたいです。
Power up your REPL life with types
Youtube: [JA] Power up your REPL life with types / tomoya ishida @tompng - YouTube
Slide: rubykaigi2023_tompng.pdf - Google ドライブ
[内容]
この講演では、型定義の情報を使用してirbの補完機能を強力なものにするためのgem katakta_irbについて理解ができます。
irbの現状として、メソッドチェーンをすると正しい補完方法を出せなく、ありとあらゆるクラスのすべてのメソッドを出してしまったり、それ がパフォーマンスに問題があるということで最新のirbではメソッドチェーンの補完は出さないようになってしまいました 。 katakata_irbは、メソッドチェーンの補完をしていきます。 また、型定義の情報を使って補完をしてくれるので、かなり便利です!
katakta_irbは、タップル型やレコード型、.is_a?などは未対応で、今後実装されていくそうです。
[感想]
私もさっそく入れてみました。
gemをいれるだけで使えるようになるので、気になった方は是非使ってみましょう!
2日目
Build a mini Ruby debugger in under 300 lines
Youtube: [EN] Build a mini Ruby debugger in under 300 lines / Stan Lo @_st0012 - YouTube Slide: slides/2023-05-11-rubykaigi/Build a mini Ruby debugger.pdf at main · st0012/slides · GitHub
[内容]
たった 200 行で Ruby だけで実装した Debugger を紹介しますという講演。
単純化した pry の再実装のようなものですが、 このコードを読むことで Ruby で実装された Debugger のエッセンスが簡単に理解できます。
Ruby で何か開発をしている人は、何かしらの Debugger を使っているはずです。
ただ、普段使っている Debugger が中でどのようなことしているか知っている人は少ないですよね。 しかし Debugger の中身を深く知っていれば、必要に応じて自分で Debugger をカスタマイズしたりできたりと応用が効くようになります。
Ruby の Debugger の基本的な機能はたった3つのコンポーネントの組み合わせから成っています。
Binding object and Kernel#Binding
Tracepoint
ruby/reline Library
これだけで簡単なデバッグに必要な、以下のようなことが実現できます。
Breakpoint
を設定して対話的にコードを実行する(REPL)Step-in
,Step-over
を使ってコードを実行するBreakpoint
を新たに追加 / 削除する
[感想]
Debugger に限らず普段使っている gem のソースコードを読むと、
動いていることとは裏腹に実装がめちゃくちゃシンプルだな...
という風に思うことが Ruby だとちょくちょくありますよね。
やはり Ruby の魔術って強力だなあと改めて思いました。
Yet Another Ruby Parser
Youtube: [EN] Yet Another Ruby Parser / Kevin Newton @kddnewton - YouTube
Slide: YARP - Speaker Deck
[内容]
Yet Another Ruby Parser は通称 YARP と呼ばれている、
Ruby の次世代のパーサーの一つです。
次に求められるパーサーを作るには主に3つの課題をクリアする必要があり、 YARP においてもこれらの点を解決するための取り組みがなされています。
- エラートレラントであること
- 高いポータビリティを持つこと
- メンテナンスしやすいこと
エラートレラントであるというのは、構文にエラーがあるコードが与えられたときでも、 何かしら意味のある結果を返すことができるということです。
エラートレラントであるパーサーを持つことで、コードの補完などを開発者に提供することができます。 IDE が充実している現代ではこういった機能は言語として必須といってもいいでしょう。
また、Ruby にはさまざまな構文ルールがあり、実行ランタイムもさまざまです。
このような世界では何か特定の実装に依存した仕組みがあると、 パーサーは限定した環境でしか使えないもの、すなわちポータビリティが低いということになってしまいます。
YARP では CRuby や、特定のパッケージの利用を前提とした実装がありません。 あらゆる環境でも利用できるパーサーとなるとのことでした。
最後にメンテナンスしやすいという点では、YARP は拡張性が高いということを挙げています。 テストコードも十分にあり、デバッグの難易度も低く、比較的簡単に新たな構文の追加ができるようになっているとのこと。
Gem としてのリリースはまだですが Ruby 3.3.0-preview1 以降のバージョンであれば実際に使うことも可能。 既に ruby/ruby のコードベースを初めとして、多くの主要な gem においても動作することが確認できているようです。
講演では Ruby のパーサーを開発することが如何に難しいかということにも触れられています。
[感想]
Ruby は開発者にとって自由度の高い書き方ができたり、
コミュニティによって多くのライブラリが産まれることで大きく発展してきた一方で、
それらを包括しなくてはならないパーサーの開発は非常にチャレンジングなんだなあと感じされられます。
The Resurrection of the Fast Parallel Test Runner
Youtube: [JA] The Resurrection of the Fast Parallel Test Runner / Koichi ITO @koic - YouTube
Slide: The Resurrection of the Fast Parallel Test Runner - Speaker Deck
[内容]
サービスの巨大化に伴い、テストの実行時間が肥大化するということはあらゆる場面で問題になっています。
実行時間を短縮するアプローチはさまざまありますが、その一つにテストの並列実行があります。
並列で実行することにより、直列で実行した時と比べて理論上は実行環境の CPU のコア数倍テストは早くなるはずです。
Minitest
には parallelize_me!
という機能があり、マルチスレッドでの並列テストの実行が可能です。
また、Rails 6
以降ではテストの数によって Minitest
を自動的に並列的に実行するようになっています。
しかし、Minitest
以外のテスティングフレームワークでは並列テストは有効になりません。
そこで注目したのが test-queue
という Gem です。
test-queue
が優れている点はまず、実行時間の最適化を図れることです。
並列実行において問題となるのは特定のワーカーの処理時間だけが長くなってしまい、 全体の実行時間がそれに引きずられて遅くなるという部分です。
同じように並列テストを行うための Gem で parallel_tests
というものがありますが、
こちらはテスト開始時にあらかじめワーカーにタスクを割り振るのでこういった問題が発生してしまいます。
これに対して test-queue
ではテストを実際に実行するワーカーが空いたタイミングでタスクを逐次 pop するため、
こういった問題が起こりにくくなっています。
次に優れている点が、Pluggable であるという点です。
基本的な処理の実装は共通であるものの、 テストランナーの部分は各テスティングフレームワークの API を実行する形になっています。
これにより test-queue
は RSpec
を初めとして、Minitest
, Cucumber
などさまざまなフレームワークで使用が可能です。
[感想]
テストコードの存在が重要だというのはもはや常識であり、
CI ツールを用いて全テストをパスさせてからリリースを行う、
というパイプラインを構築するのは一般的なプラクティスとなっていますよね。
ただこれにより、テストの遅さがリリースまでのリードタイムを遅くする要因となってしまうことになります。 我々のプロダクトでもテストを如何に早くするか、ということは改めて考えないとなと思います。
Multiverse Ruby
Youtube: [JA] Multiverse Ruby / Chris Salzberg @shioyama - YouTube
Slide: Multiverse Ruby - Speaker Deck
[内容]
登壇者の @shioyama さんが作成した gem である im の紹介となる講演です。
Ruby においてプロダクトを拡張する場合 require
が利用できます。
また Rails でも採用されている Zeitwerk などの autoload
を利用する場合もあるかもしれません。
この場合は明示的にファイル名を指定しなくてもモジュール名からファイルを探索してロードを行ってくれます。
ただこれら両方において問題となるのが名前空間の衝突です。
ロードされたモジュールは共通の permanent root となる Object
の名前空間に置かれます。
Foo
というモジュールをロードした場合、
厳密には Object::Foo
になり、 Bar
なら Object::Bar
となります。
モジュールの開発者は自由に命名を行うことができませんし、 モジュールを利用する方も名前が衝突しないように気を使いながら開発する必要があります。
im
では匿名モジュールの仕組みを使ってこれを解決しています。
匿名モジュールは作成された時点では名前空間を占有しません。
mod = Module.new => #<Module:0x000000015316e1b8> mod::Foo = Module.new => #<Module:0x000000015316e1b8>::Foo
匿名モジュールに定数を与えた時点で名前が設定されるのですが、
この時 Object
ではなく、自身で設定した独自の名前が root になります。
irb(main):019:0> MyFoo = mod::Foo => MyFoo
このツリーの中でモジュールを拡張しても共通の名前空間は占有しません。
もし MyFoo
という名前空間で Bar
をロードすると MyFoo::Bar
となり、
他に MyBaz
という名前空間があれば、その中では MyBaz::Bar
となるので同じ名前で異なる機能をロードできるわけです。
[感想]
プロダクトが大きくなってくると名前の衝突って結構面倒な問題です。
我々のサービスでも意図せず名前が衝突してしまって不具合の原因になったこともあります。
また、名前が衝突しないように prefix をつけたり、名前空間の階層をたくさん作ったりしますが、 シンプルな名前を自由につけられるようになるのは DX 向上の面でもありがたいです。
Tips and Tricks for working in the MRI Codebase
Youtube: [EN] Tips and Tricks for working in the MRI Codebase / Jemma Issroff @jemmaissroff - YouTube
Slide: Kaigi 2023.pdf - Google ドライブ
[内容]
MRI(CRuby) のメンテナンスの手順について説明してくれている How to 的な講演です。
実際にあった issue を題材にして、そのバグの調査を行う過程を見ながら解説をしてくれています。
調査のためには実際にコードの挙動を確認しなくてはいけません。
まずローカルの開発環境に ruby をクローンしてビルドしていきます。
この時全ての機能をビルドすると時間がかかるので、miniruby
という軽量版としてビルドすることも可能です。
次にテストコードを作成して実行しバグの再現をしてみます。
バグが再現することがわかったら、問題となっているコードを探していきます。
ruby で実行可能なコードは C のソースの中では rb_define_
という prefix がついている関数によって定義されていることが多いです。
例えば sum
という ruby の関数が定義されている場所を探すなら、rb_define_method.*sum
で grep すれば良いわけです。
また、クラス単位でファイルが分かれていることも多いです。
例えば Array
クラスの関数は array.c
に定義されています。
このように該当のクラスの .c
ファイルを探すというアプローチもあります。
問題の C のコードを見つけたらデバックしていきます。
ruby のコードのデバッグには irb などが用いられますが、C のコードのデバッグには lldb
または gdb
を利用します。
irb と同様にブレークポイントの設定やステップ実行などをしながらバグの原因をさらに特定していきます。
[感想]
RubyKaigi では尖った技術を駆使した最近の成果発表が多い一方で、
このような普遍的な How to を紹介する講演は少なかったのでとても印象に残ってます。
聞いてみるとなんだか自分にも CRuby のメンテナンスができそう(な気がしてくるだけ)になってきます。 僕含め RubyKaigi でこういった世界に初めて触れて面白そう!と思った方にはぜひ聞いていただきたい講演です。
Optimizing YJIT’s Performance, from Inception to Production
Youtube: [EN][Keynote] Optimizing YJIT’s Performance, from Inception to Production / @maximecb - YouTube
Slide: YJIT RubyKaigi 2023 slides - Google スライド
[内容]
Ruby 3.2 よりいよいよ YJIT が本番アプリケーションでも実用的だというアナウンスがありました。
この講演では YJIT の開発の歴史を振り返るとともに、 実際に Shopify が本番アプリケーションに YJIT を投入してどの程度パフォーマンスが向上したのか?についてお話ししてくれています。
JIT とは Just In Time の略で、プログラムの実行時にコンパイルを行うのが特徴です。
表面上はインタプリタの様に振る舞うため、 Ruby のようなインタプリタ言語でも違和感なく開発が行えます。
また、事前コンパイルと違い実行時の環境に応じて最適化を図れるため、より優れたコードを生成できる可能性もあります。
YJIT は初め Ruby と同じくインタプリタ言語である MATLAB の JIT コンパイラが原型となっています。
そして登壇者である Maxime 氏が Shopify に Join し、μJIT -> YJIT へと開発を進め今に至ります。
実際に YJIT は多くが Ruby で作成された Shopify の Website に本番投入され、既にパフォーマンスの測定がなされています。
2023年1月地点で応答速度が 6% 向上しており、 さらに改善が図られた2023年4月にはなんと 18% もの速度向上が認められたようです。
また以前は Warm up のタイミングで膨大にメモリを消費する点が問題となっていましたが、 開発が重ねられた2023年以降は YJIT を使わない場合とほとんど変わらないレベルにまでなっているそう。
[感想]
Ruby でアプリケーションを開発している人間にとって、
採用するだけでパフォーマンスが向上する YJIT を使わない手はないよなと思いました。
我々のプロダクトでもガンガン使っていきたいです!
3日目
The Adventure of RedAmber - A data frame library in Ruby
Youtube: [JA] The Adventure of RedAmber - A data frame library in Ruby / Hirokazu SUZUKI @heronshoes - YouTube
Slide: The Adventure of RedAmber - A data frame library in Ruby - Speaker Deck
[内容]
登壇者の Suzuki さんが開発に携わっている RedAmber というライブラリの紹介になります。
RedAmber はデータフレームを作成、操作するためのライブラリで、 同様の機能を提供しているものは他言語だと Python の Pandas や R の dplyr などが有名です。
データフレームは行方向でデータを操作したり、列方向でデータを操作したりすることができ、 非常に柔軟かつ簡単にデータ処理を行えることが特徴になっています。
RedAmber では各関数の戻り値が Ruby の Array
や Hash
になっていたり、
Ruby のシンタックスによく似た表現が多く使えるため、
普段 Ruby を使う人にとってはかなり直感的に操作を行うことができそうです。
また、Suzuki さんは普段はエンジニアではない仕事をしているそうで、 こういった OSS 活動はアマチュアとして行っているそうです。
[感想]
世界中のあらゆる人が Ruby を一緒に盛り上げているんだなあと感じられる、
Ruby コミュニティの素晴らしさもわかる講演でした!
Ruby + ADBC - A single API between Ruby and DBs
Youtube: [JA] Ruby + ADBC - A single API between Ruby and DBs / Sutou Kouhei @ktou - YouTube
Slide: Ruby + ADBC - A single API between Ruby and DBs - Kouhei Sutou - Rabbit Slide Show
[内容]
データベースとアプリケーション間でデータを読み書きするときには多くのオーバーヘッドが発生します。
これはデータが少ないうちはまだ良いですが、 大量のデータになってくるとそのオーバーヘッドによる遅延はとても許容できるものではありません。
講演内で紹介されている ADBC はそのような大量データの読み書きに適したライブラリです。
Read 時には結果セットを分割し並行に処理を行うことで高速化を実現し、 Write 時にはバルクインサートを実行し最適化された大量データの書き込みを行うことが可能です。
また、クライアント側で扱うデータには Apache Arrow データフォーマットを採用し、 こちらもデータベースのデータとの変換コストが非常に安くなるよう設計されているようです。
既に Postgres の一般的なクライアントである libpq
との比較では、
1カラム1000万レコードの読み取りで2倍の高速化を実現しているとのこと。
高速化以外の面でも、抽象化された API をインターフェースに持っており、 クライアント側ではデータベースの違いを意識することなく利用できる使い勝手の良さも魅力です。
[感想]
Ruby は Rails のイメージが強く、Web アプリケーション向けの言語という印象を持つ方も多いのではないでしょうか??
こういったデータ処理の分野での利用が盛り上がって、 AI やデータ分析の現場でも Ruby の存在感が増していってくれば Rubist にとってとても嬉しいことですよね!
Code indexing: How language servers understand our code
Youtube: [EN] Code indexing: How language servers understand our code / Vinicius Stock @vinistock - YouTube
Slide: Code indexing: How language servers understand our code - Speaker Deck
[内容]
ruby-lsp は Shopify が提供する Ruby のためのモダンな LSP (Language Server Protocol) です。
LSP はエディターと連携して開発者体験を向上させるための様々な機能を提供してくれます。
今回の講演では Go to definition
機能がどのように実装されているのか?というのを詳しく紹介してくれています。
Go to definition
は具体的にいうと、呼び出している関数やクラスなどが定義されているファイル、場所にジャンプする機能です。
エディター上でクラス名などの一部をクリックすると、 ファイル名とクリックした場所を含むオブジェクトがどこにあるのか?という index 情報を LSP にリクエストします。
index 情報にはファイル中の何行目の何文字目にそれがあるのか?という情報が含まれており、 ファイル名と組み合わせることで何がみたいのかを一意に特定できるわけです。
LSP 側では index 情報を受け取って、その場所にあるオブジェクトは何か?を特定し、 また、その定義がある場所をエディター側にレスポンスしなくてはいけません。
このためにはあらかじめ全てのコードの index 情報を持っておく必要があります。 なので LSP では立ち上げ時にこれを行っています。
また、LSP 立ち上げ後のコードの変更に対応できるよう、 変更を検知すると index 情報も併せて更新するよう設計されています。
[感想]
これらの機能は Ruby で開発されていて、
この講演では設計/実装内容もかなり詳しく説明されています。
気になるかたは動画の方を見ていただけますとかなりおもしろいと思います!
Unleashing the Power of Asynchronous HTTP with Ruby
Youtube: [EN] Unleashing the Power of Asynchronous HTTP with Ruby / Samuel Williams @ioquatix - YouTube
Slide: presentations/2023/Unleashing the Power of Asynchronous HTTP.pdf at main · ioquatix/presentations · GitHub
[内容]
HTTP はあらゆるデータをクライアントとサーバー間でやりとりするための通信プロトコルです。
現在のインターネットの根幹をなす技術と捉えて差し支えないでしょう。
HTTP は現在から 30 年以上前に誕生し、当初はテキストファイルのみのやり取りしかできませんでしたが、 Web の発展と共に画像や音声データ、動画までをサポートし徐々に進化してきました。
中でも HTTP 1.0 は広く我々に受け入れられ、 長らく Web の世界のスタンダードとなっていましたが、今はその転換機にあると言えます。
まず初めに HTTP 2.0。特に重要なアップデートがストリーミングの多重化による並列処理です。
HTTP 1.0 まででは1つのコネクション内で一度に1つのリソースのやりとりしかできませんでした。
しかし、HTTP 2.0 では同時に複数のリソースを処理できるため、 高速化が期待できるのと、大きなコンテンツを取り扱うと他の処理が待たされる(HoLブロッキング)のを回避できます。
次に HTTP 3.0。ここでは HTTP 2.0 にあった欠点をさらに克服しています。
HTTP 2.0 では並列処理といってもコネクションは同じなので、ここが途絶えれば全ての処理が止まります。 しかし HTTP 3.0 ではコネクションレスであり多重化されたストリームは独立で、他の処理に影響を与えることはありません。
また固有のコネクションIDを持ち、これらは IP アドレスなどが変わっても固定です。 すなわち途中で通信が途切れて別のネットワークに変わっても継続して処理を行うことが可能です。
これらの機能は通信が不安定になりがちな、屋外でのインターネットの利用において非常に強力です。
今や多くのユーザーがスマートフォンからインターネットを利用しており、 HTTP 3.0 はこれからのスタンダードになっていくことが予想されます。
ただ、Ruby にて HTTP 2.0, 3.0 をサポートしているアダプタはほとんどありません。
登壇者の Samuel 氏は falcon という HTTP Server の開発を進めており、 既に HTTP 2.0 はサポート済み、年内には HTTP 3.0 のサポートを開始するようです。
[感想]
ゴリゴリにネットワークの話で、RubyKaigi のなかでも異色を放っていた講演でした。
ただ自分のような Web 業界の人間にはとても刺さる内容で強く記憶に残っています。
Parsing RBS
Youtube: [EN][Keynote] Parsing RBS / Soutaro Matsumoto @soutaro - YouTube
[内容]
Ruby の型定義を記述するための RBS のパーサーを改善しました、という講演です。
RBS のパーサーはこれまでエラートレラントではなかったので、 シンタックスエラーが発生するような場合に構文解析が中断し、 そのエラー理由を知ることもできないという状態でした。
改善されたパーサーでは3つのアプローチでエラートレラントを実現しています。
まず初めに MissingTree
の導入。
正しい構文には始端となるトークンがあれば終端となるトークンが対となって存在する必要があります。
例えばクラスを定義するための class
というトークンがあるなら、その後に end
がどこかで現れる必要があるわけですね。
もし終端のトークンが存在しないときはシンタックスエラーを raise する代わりに MissingTree
としてノードを作成し、構文解析を先に進めます。
次のアプローチは不要なトークンをスキップすることです。
attr_reader foo: -> String
のような場合ですが、
本来 attr_reader
をパースするとき :
の後に ->
がくるのは構文エラーになるのでここで解析が終了してしまいます。
特定のトークンの後に来ても問題のないトークンをあらかじめルールとして用意しておき、 ルール外のトークンはスキップすることでこの問題を回避できます。
最後がネストされた定義のパースに関する問題です。
例として以下のような構文を見てみましょう。
class Foo class Bar def initialize end
Bar
クラスに終端がなく、initialize
関数にも終端がありません。
このような場合どちらも MissingTree
として Bar
の関数として initialize
関数があると解析されます。
これを以下のように変更したらどうでしょう?
class Foo class Bar; end def initialize end
Bar
クラスが編集されて終端記号が補われました。
編集後は initialize
関数は外側のクラスの Foo
の関数として解析される必要があるわけです。
これを解決するためには終端記号を最後に補った場所に [EOF]
のようなトークンを追加します。
再度パースを行う際に [EOF]
を見つけたらネストを抜け、
外側のメンバーとして解析を行うようにすることでこの問題を解決しています。
[感想]
パーサーに関する講演は RubyKaigi 中にも多くありましたが、
みなさんそれぞれ違ったアプローチで問題解決に取り組んでいました。
比較しながら聞いてみるとおもしろいと思います!
来年は、沖縄で会いましょう!
ありがとうございました!
株式会社エニグモ すべての求人一覧