ENECHANGE Developer Blog

ENECHANGE開発者ブログ

RubyKaigi 2022 参加レポート : Day 3

こんにちは! ENECHANGEで働いているishibashi(id:rubita_isi)です。

okamotoと一緒にRubyKaigi2022にオフラインで参加してきました!

Day3について書いていきます。

今回も「私がRubyKaigi 2022に参加して感じたこと」、「私が参加したセッションで話されたことの要約と感想」を主に書きます。

Day1, Day2の記事をまだご覧になっていない方はこちらも是非御覧ください。

tech.enechange.co.jp tech.enechange.co.jp tech.enechange.co.jp

error_highlight: user-friendly error diagnostics

要約

Ruby3.1におけるerror_highlight

  • Ruby3.1ではerror_higlightというエラー箇所に下線を出す機能が追加された
    (以下は実際の出力例)
% ruby test.rb
test.rb:1:in `<main>': undefined method `revese' for "Hello":String (NoMethodError)

"Hello".revese
       ^^^^^^^
Did you mean?  reverse
               reverse!
  • Ruby3.1では、NameError / NoMethodErrorのみに対応していた

Ruby3.2の新機能と今回のテーマ

  • Ruby3.2においては、以下の新機能に対応する

    • ArgumentError / TypeErrorに対応
    • Railsのエラーページをサポート
  • 今回は、新機能導入にあたって生じた問題と解決方法を紹介したい

非互換問題への対応

  • Ruby3.1ではException#messageをオーバーライドしてerror_highlightのメッセージを表示していた
  • このアプローチでは、以下のように互換性の問題が生じる
    • テストの互換性
      • 多くのテストでは、エラーメッセージをチェックする
        expect { ... }.to raise_error("foobar")
      • そのため、Exception#messageの振る舞いを変えると互換性に問題が生じる
    • エラーログの互換性
      • 多くのエラーログでは、#messageは1行の文字列を返却することを期待する
  • Exception#detailed_messageを導入することで、問題の解決を図った

  • フレームワークは#detailed_messageを使用したいかもしれないので、修正が必要
    • ex.) Rackの修正パッチはマージ済
    • SentryとDatadogは#detailed_messageのサポートを約束してくれた

下線の間違いへの対応

  • Rubyのエラープリンタはmessageをエスケープするので、下線の位置がずれてしまう

  • 解決方法は、Rubyのエラープリンタでエスケープするのをストップするだけ
    • この解決方法は約1ヶ月もの期間を要した。なぜか?
  • そもそもこのエスケープは、セキュリティ上の配慮で行われていた
    • ターミナルには危険なエスケープシーケンスが存在するため
      ex.) ファイルを作ったり、ユーザーが入力したかのように振る舞う
  • しかし、この心配は今は不要と判断できたためエスケープをストップした
    • 元になった記事がとても古く(2003年)、本来はターミナルの責任であるとも言及されていた
    • 現在の主なターミナルでは、こういった危険なエスケープシーケンスはサポートしていない

Railsへのサポート

  • error_highlight APIを導入することで、Railsのエラーページでerror_hightを表示できるようになった

感想

  • error_highlightの新機能でRuby3.2(とRails)がさらに便利になることを期待します!
  • 新機能の追加一つで、これだけの苦労や配慮が必要になるのかと、maintainer, committerの皆さんには頭が下がる思いです
  • mameさんが仰っていたように、自分が使用するフレームワークでバグを見つけたらpatchのPRを送るようにしたいです

Let's collect type info during Ruby running and automaticall

要約

何をしたのか

  • Rubyの実行時の処理をトレースしてRBSを生成するrbs-dynamicを作成した

動機

  • RBSファイルは書きたくないが、型の恩恵は受けたい
  • 静的解析である`TypeProf`とは別のアプローチをしてみたかった
  • RBSに対して関心を持ちたい / 持ってほしい

実装時のイメージ

  1. `TracePoint`を利用してRubyのメソッド呼び出し情報を集める
  2. rbsライブラリを用いて、収集したメソッドのメタ情報をRBSのデータに変換する

実際に使ってみる

  • 2種類の使用方法がある

    • Ruby上からRBSデータを生成する
      • RBS::Dynamic.trace_to_rbs_text { #procedures }のブロック内で呼び出されたメソッドから生成
    • rbs-dynamicコマンドで生成
      • 以下は、ishibashiのローカル環境でrbs-dynamicコマンドを実行した結果
  • sample.rb

class FizzBuzz
  def initialize(value)
    @value = value
  end

  def value; @value end

  def apply
      value % 15 == 0 ? "FizzBuzz"
    : value %  3 == 0 ? "Fizz"
    : value %  5 == 0 ? "Buzz"
    : value
  end
end

(1..20).each { FizzBuzz.new(_1).apply }
  • 実行結果
rbs-dynamic trace sample.rb
# RBS dynamic trace 0.1.0

class FizzBuzz
  private def initialize: (Integer value) -> Integer

  def apply: () -> (Integer | String)

  def value: () -> Integer

  @value: Integer
end

RBSを自動生成する上で工夫した点

  • Interface型を自動で定義できるようにした

    • rbs-dynamicのコマンドオプション: --use-interface-method-argument
  • メソッドの定義元や参照先の位置情報をRBSのコメントに埋め組むようにした

    • rbs-dynamicのコマンドオプション: --show-method-location
  • `Symbol`型 + `Symbolの値`で型定義するようにした

    • RBSでは`Symbolの値`を型として利用できる
    • rbs-dynamicでは`Symbol`型 を基本としつつ、Symbol | :hoge | :foo | :barのように定義するようにした
    • rbs-dynamicのコマンドオプション: --with-literal-type

今後の課題

  • RBSファイルをどう生成するのか?(いつ? / 既存ファイルとコンフリクトしないようにするには?)
  • 「動いているコードが正となる」ことのギャップ(意図しない型も動いているコードが正になる)
  • 型の抽象度を上げてみる
    • ex.) class Sub1 < Baseclass Sub2 < Baseがある時にSub1 | Sub2Baseと定義する、とか
  • そもそもRBSをどう活用するのか?(`Steep`以外での活用場面)

感想

  • RBSはまだまだ発展途上という感じで、様々な方が面白いチャレンジをされているのだなと思いました
  • 動いているコードを解析してRBSを作成するアプローチは面白いだけでなく、示唆に富むものでした
  • 実際に`TypeProf`より精緻に解析されているケースを見せていただき、感動しました

Why is building the Ruby environment hard?

要約

セッションの目的

  • Ruby, RubyGems, ruby-buildのmaintainerをしている立場から、ここ最近のビルドエラーの話題を拾い、一人でもビルドエラーに時間を費やす人を減らしたい

各カテゴリから一つずつエラー例をピックアップ

Ruby: Ubuntu 22.04でビルドができない
Gem: bundled gemsがビルドできない
Ruby3.2 (予想): YJITがRustになった

ビルドエラーを乗り越えた先へ

  • ソフトウェアは何もしないと壊れる
    • ソフトウェアを動かす環境 (OS, ミドルウェア, ハードウェア)は絶えず変化している
    • 「何もしないと壊れる」のは当然である
  • ソフトウェアが変化に適応する必要がある
    • OSやライブララリなどが変わった時にはまず動かしてみる
  • コミュニティを活用する
    • 不具合があった場合は、htts://bugs.ruby-lang.org/やGitHubの各種リポジトリで報告
    • ruby-jp slackや地域ミートアップで聞いてみる

感想

  • 私もご多分に洩れず環境構築に苦労した経験があるので、こういった具体的なTipsの共有は大変ありがたかったです
  • 「ソフトウェアは何もしないと壊れる」は肝に銘じて日々の運用をしていきたいです
  • 10月リリース予定のmacOS13.0 (Ventura)へのアップデートは慎重を期した方が良さそうです(!)
    • Rubyがビルドできない、`test_process.rb`のforkのテストが動かない等の問題があったようです
    • 解決の目処自体は見えていそうです(皆さんの努力に感謝・・😭)

Fast data processing with Ruby and Apache Arrow

要約

前提知識

  • Apache Arrow

    • 列データを処理するデータ分析アプリケーションを開発するための、「言語に依存しない」ソフトウェアフレームワーク
    • 「言語に依存しない」:Rubyコミュニティは、共通の実装を言語を超えて共有できる
  • Red Arrow

  • Red Data Tools project

    • Ruby用のデータ処理ツールを提供するプロジェクト

本セッションのゴール

  • データ処理でRubyを使いたいと思ってほしい
  • Red Data Tools projectに参加してほしい

Rubyのデータ処理高速化の2つのアプローチ

  • 別プロセスによる解決
    • DB等の早いデータ処理モジュールを使用
  • 同一プロセスによる解決
    • 他の速い言語でコアの機能を実装

別プロセスによる解決

  • 今のRubyではよくあるケースだが、レスポンスが大きい場合に問題となる
    • シリアライズ・デシリアライズのコストが大きいため、送信・受信処理が遅くなる
  • Apach Arrowフォーマットを利用すればシリアライズ・デシリアライズのコストをほぼ0にできる

  • Apache Arrow Flight SQL

    • gRPCベースのプロトコル
    • Apache Arrowフォーマットに特化
    • Apache Arrow Flight SQLは、MySQL, PostgreSQL等の既存のDBではサポートされない可能性が高い
      • 新しいSQLDBやBIツールはデフォルトでFlight SQLをサポートするだろう
    • 次は、Fligtht SQL用のActive Recordアダプターを実装するといいのでは?
      • Red Data Toolsで開発しようぜ!
  • ADBC: Apache Arrow Database Connectivity

    • 任意のSQL DBに接続できる高速なAPI
    • Flight SQLが最速のドライバーであるが、すべてのSQL DBに同じAPIでアクセスできるのは便利
    • 現在、Rubyバインディングを実装中
      • Red Data ToolsでADBC用のActive Recordアダプターを開発しようぜ!

同一プロセスによる解決

  • 今のRubyの使われ方だとあまりないケース
    • ユースケース:ローカル・リモートストレージにあるデータ処理
  • 高速にデータ処理ができる他の速い言語で実装されたライブラリーが必要

    • 速い言語:C/C++, Rust, Julia etc
  • C++の場合

    • Apach Arrow

    • DuckDB

      • データ分析向けのSQLiteのようなもの
        • Duck DBと高速にデータ交換できれば、高速データ処理を実現できる
      • Apache Arrow C data/stream interface
      • 高速にデータ交換するためのC ABI
  • 低レベルのAPIは整備できた

    • 高レベルのAPIを実装しようぜ!

感想

  • Rubyでデータ処理を扱おう/高速化しようという試みは、他のセッションでもあったので、ホットな話題なんだなという印象を持ちました
  • Apache ArrowプロジェクトのProject Management Comittee ChairであるSutouさんがRubyコミッターであることは、Ruby業界にとってとても幸運なことだと思いました
  • 私自身が業務でデータ処理を扱うことはあまり想定されない気はしますが、話題としては興味深かったです
  • 特にADBC用のActive Recordアダプターが開発されれば、既存のRailsプロダクトの高速化につながる可能性があります

Closing session

  • 閉会式では、運営スタッフの皆さんが壇上で挨拶し、会場からは万雷の拍手が送られました。
  • 私自身は初めての参加でしたが、3年ぶりのオフライン開催ということで、ベテラン参加者の皆さんは感無量という感じでした!
  • 次回のRubyKaigi 2023は松本で行われるとのことです!実費でもいいので、また参加したい!
  • 次回までに、Rubyコミュニティになんらかの貢献をしたいです!
  • Ruby is fun!