ENECHANGE Developer Blog

ENECHANGE開発者ブログ

RubyKaigi 2019 参加レポート : Day 2

ENECHANGEで働いている id:tetsushi_fukabori です。

昨日に引き続きRubyKaigi 2019 Day 2の様子をお伝えします。

本記事で書くこと

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

RubyKaigiはYouTubeチャンネルがあるので、講演を全て観たい方はこちらもどうぞ(本記事執筆時点ではまだ2019年分はアップされていません)。

www.youtube.com

本日のお写真

高菜、食べてしまったんですか!
博多といったらラーメンですよね

界隈では「高菜」で有名なラーメン屋さんでお昼を食べました。なお高菜は原材料が不足しており提供停止されていました。

本文に入る前に:RubyGems.orgの多要素認証を設定しましょうのお知らせ

RubyKaigi 2019でRubyコミッターが発表する前には必ずアナウンスされていた重要事項ですのでここでもお知らせです。

  • RubyGems.orgのアカウントに対して攻撃が行われている
  • 攻撃防止のため、現時点でRubyGems.orgのアカウントを持っている方、これからRubyGems.orgのアカウントを作成される方は必ず多要素認証(MFA: Multi-Factor Authentication)を設定してください
  • 実際にbootstrap-sass gemへの攻撃が行われ、version 3.2.0.3に攻撃のコードが含まれていました

みなさんでコミュニティを守っていきましょう!

Day 2のセッション

All bugfixes are incompatibilities

Ruby安定版のメンテナである発表者がメンテナの戦いの日々を伝えてくれました。二日目のキーノートセッションです。

改めて安定的なメンテナンスを継続する、というのは大変なことなんだなあと感じます。 Rubyも歴史を積み重ねて、最初のころからあるソースは継ぎ足し継ぎ足しで大変なことになっているようで、そりゃ手を出すとバグることもありますよね…。

  • Rubyの安定版のメンテナンスとは?
    • Rubyのバージョン管理
      • Rubyはsvnでバージョン管理されている(が、2019/04/22にgitへ移行したそうです!おめでとうございます!)
      • Rubyはtrunkがメイン(gitでいうmaster)ブランチ
      • 安定板はtrunkから切られ、修正はtrunkへ、必要なものはbackport(gitでいうチェリーピック)して安定版に入れる
      • 安定板ブランチにそれぞれメンテナがいるので、サポートできるバージョン数はメンテナの人数と同じ
      • trunkにはリリースマネージャーがいる
      • 順にメンテナがスライドしてる(一つ古い版、二つ古い版、trunkにそれぞれメンテナがいる)
    • 安定版メンテナの仕事
      • 全般
        • 日々のtrunkコミットを監視してtrunkからの修正を安定板ブランチへbackport
        • 安定版パッケージのリリース
        • 脆弱性対応
          • セキュリティ対応は全ての安定版で足並み揃えなきゃいけないから大変
      • メンテナはtrunkのクローズされたredmineのチケットを見てる(backportのため)
      • メンテナはボランティアでやってる
        • どの程度の頻度で安定板リリースできるかはメンテナの人数に依存
        • 今は毎年安定板が出ているし、メンテナは二人だから過去2バージョンが安定版、古いのはEOL
        • Rubyの進化を続けたいから安定版リリース頻度は下げたくない
        • じゃあもっと長く安定版メンテナンスがいるのなら、メンテナがもっと必要
        • また、多分今後はメンテナの世代交代が必要(なぜなら「人間には1年に1歳歳をとる脆弱性がある」)
        • ここでは未来のメンテナへ申し送り事項を伝えたい
  • 未来のメンテナへ申し送り事項
    • メンテナには何が必要?
      • Rubyの実装について「広く浅く」知っていること
      • ある程度継続的に活動できること
      • メンテナンスポリシーに対する理解があること
        • バグは入れる、featureは入れない
        • trunkのコミットを見て、安定板への受け入れ要否を見極めなきゃいけないが、これが難しい
        • 例:IO.read
          • 第一引数にファイル名文字列、中身を読み込んでファイル名を返すメソッド
          • 実はIO.readは頭にパイプつけてコマンドをかくとコマンド実行できる
          • 外部入力からコマンド与えられちゃうから脆弱性では?という意見があった
          • Ruby的には仕様どおりだけど確かに危ない。禁止する?議論 →結論としては変更しない
          • ところがFile.readもIO.readと同じことができる →Fileに対してコマンド実行ができるのは流石に変では?Fileはブロックするか?
          • github調べたらFile.readでコマンド実行&結果取得を期待しているリポジトリあった
          • なのでFile.IOを修正してリリースしたらそのリポジトリが壊れちゃう…じゃあ警告を出すようにしよう
          • さて、この対応はバグ修正?でも取り込むと非互換になってしまうが?
    • 自身のメンテナとしての過去の失敗
      • 不具合修正(GC二度打ち)と言われてたけど性能改善だったコミットをbackportした
        • 見た目安全そうだから混ぜた
        • win版のCI失敗…revert
        • 安定版はバグ修正が大事なのに、バグを取り込んでしまった…。
      • 複雑な条件でsuperを叩くとメソッド探索時に無限ループ
        • 修正のために追加した引数がnilになることがあった
        • これにより特定の条件で不正メモリエラー
        • バグ修正がバグを呼ぶことがあるので注意がいる…。
      • refinements
        • "==="の挙動を一部変更
        • 考慮不足バグ
      • 文法周り
        • 三項演算子直したらハッシュリテラルが壊れた。Syntaxエラーになる。
        • 三項演算子とハッシュリテラルが同じコロン記号を使っていたため、パーサーでバグが起きた
        • パーサーの挙動はめっちゃ難しい(「parse.yは魔境」)
        • 事前にテストで防ぎきるのは超大変
        • Syntaxエラーはファイルロード時点でエラーになるのでモンキーパッチも効かない。辛い。
      • デフォルト値なしキーワード引数
        • デフォルト値ないとカッコを省略したメソッドでSyntaxエラー
        • またもやハッシュリテラル(コロン)
        • エラーの重要性だけで見ると本件のキーワード引数の方が修正すべきエラー
        • だけど、この時点ではキーワード引数はリリースされたばっかりだったから、すぐに修正しなくても影響は極小
        • 引きずられて出てきたSyntaxエラーの方が影響が大きい
        • まだもっと慎重にレビューしときゃよかった…。
      • 特定の文法でパース時にSyntaxエラー
        • いつも通り直したら別のSyntaxエラー
        • なんとこのバグはRuby1.9.3の頃からあった
        • この文法を使っていれば必ずSyntaxエラー(ロード時エラー)なので、じゃあそもそも世の中のコードにはこの文法を使ってるアプリはなかった
        • なのに直した方でSyntaxエラーを起こしたら、むしろ被害が広がる…。
      • FIFOを呼び出したらプロセス全体がIOブロックされる
        • FIFO使ってる時にIOブロックするのをやめた
        • そうしたら突然処理性能が低下するバグが発生
        • 実は裏の処理的にはgemをロードする時に何回もファイルリードがされていた
        • (FIFOを使っている)File.openでファイルの存在を確認してるから、IOブロックをやめたことで何度もスレッドが切り替わって重くなっていた
        • 誰もFIFOなんかロードしない、もともと誰も苦しんでいなかったのに!
    • 現実的になれ
      • 困っている人のためにやれ
      • 時には冷酷な判断(少数が困っているバグを直してより大きなユーザーにダメージを与えられない)をしろ

リリース済みサービスの運用保守にも通じる話がたくさんありますね。 触ると危ない機能があったり、多少のバグは安定のために飲み込んだり、日々みなさん戦っているかと思います。 Rubyもそうやって支えていただいているんですね。

Better CSV processing with Ruby 2.6

Ruby2.6のCSVライブラリで何がどう良くなったか、をコミッタが解説する発表。

みんな大好きCSVをRubyで扱うライブラリがRuby2.6でだいぶ高速化されたようです。

  • 2.5→2.6の読み込み
    • 単純なCSVの場合で1.7倍早くなってる
    • ダブルクオート囲みの場合で2倍
    • ダブルクオート内にカンマがある場合で1.5倍
    • ダブルクオート内に改行コードがある場合で2.7倍
    • 特にただのダブルクオート囲みのCSVは最適化したことでだいぶ早くなってる
    • マルチバイト処理でも早くなってる
  • 2.5→2.6の書き込み
    • generate_line 2.4倍
    • CSV#<<は1.6倍
    • 複数行を書き出すときはgenerate_linよりCSV#<<の方が10倍早い!
      • 「複数行は気をつけて」
  • 複雑なクオートのパースをどうしたか
    • Ruby2.6ではStringScannerを使っている
    • String#splitは早いけどコードが複雑にる。しかも複雑になればなるほど遅くなる。
    • StringScannerは読みやすくかける!複雑になっていっても性能も劣化しない!
    • 一方でStringScannerは単純なCSVだとそんなに早くないので、split使うようにしている
  • 一般的に「なんでもできる機能」は遅くなりがち。ケース別に早くなる場合があるので方法を選ぼう。
  • 大事にしていたこと
    • 後方互換性
      • アップデートで挙動が変わるのはバグ
      • テストを整理してベンチマークをつける
        • 各テストを理解しやすく
        • メンテナンスしやすく
      • ベンチマーク
        • 性能劣化を検知
        • benchmark_driver gem
          • yamlで書けて便利
          • 複数gemバージョンで比較可能!→性能劣化を検知できる
        • ベンチマークがある点が性能を気にしている
          • みなさんもyamlかくところからCSVライブラリ開発に参加してみては!
          • ベンチマークがあるところから性能改善にやっていきます!
  • 今後はstring#split、stringscannerも早くしていきたい
    • PRも出してる
  • (標準ライブラリのCSVとは違うけど)FastestCSVというgemもある
    • Cで実装されてるから早い(ベンチマークではFastestCSVが勝っている)
  • 今後
    • エンコード変換周り高速化
    • シンプルなケース用のパーサーをCで書くことで高速化
    • XMLのパースも早くしたい

Ruby遅い遅い言われていますが(これについては色々と議論がある)、コミッタのみなさんも高速化は意識されているようで着実な改善をされています。

「ベンチマークのフレームワークを整えて、ベンチマークが設定されているケースから高速化していく」というのはとても良い考え方ですね。 処理を早くしたい箇所はユーザーしか分からないから、「こんなケースだと遅くなって困る」をベンチマークの形で開発者に伝えようということですね。

Ovto: Frontend web framework for Rubyists

「最高のフレームワークができた」「思いつきで作ったらうっかり最高になってしまった」というパワーワードから始まったRubyで書けるフロントエンドフレームワーク「Ovto」の発表です。

発表の冒頭にみんなが触れるデモ環境が提示されたのですが、Basic認証がかかっており誰もさわれず…。 発表直後に認証を外すコミットがされていたのは面白かったです。

  • 発表者は普段からDIY的にプログラムを作っている
    • 「自給自足プログラミング」「Rubyはgemが多いから自分で欲しいものを自分で作るのに適してる」「スクリプト言語だからささっと作れる」
  • DIYプログラムをどうやっているか
    • 桜VPS借りてて、webアプリ作ってモバイルアプリっぽく使ってる
    • モバイルアプリ作成のスキル習得は大変
    • webの技術を覚えておけばVPSとかに置くだけでなんちゃってモバイルアプリになるし、自分用ならそれで十分
    • でも作りにくいものもある
      • jQueryだとやりにくいことがある
      • ReactはVirtualDOMなどの恩恵もあり作りやすい
        • シングルステートで作りたいのでreact-reduxを使うが、大きなアプリむけのものなので「小さなアプリを作るときは自分が使わない機能がつらみになる」
      • hyperapp はどうか
        • 軽い
        • 小さくて機能が多い →rubyに移植すると嬉しいのでは?
    • Opal というコンパイラ
      • ruby → jsをコンパイルしてくれるので、ブラウザ側のコードをrubyで書ける
      • hyperapp x Opal = Ovto !
  • Ovto
    • hyperappをそのまま移植すると「Rubyっぽくない」書き方になるので、機能は1:1対応ではない
    • demo
      • 実際に目の前でコード書いて簡単なwebアプリを作るdemo
      • Rubyコードでフロント側の処理を書き、数分で動くデモページを作っていました
    • 設計の考え方
      • 「プログラミングはもともと楽しいもの。つらみをとれば楽しくなるはず!」
      • 「つらみとは覚えることが多い、エラーがわからないなど」「親の顔より見たエラーもある」
      • エラーも極力わかりやすくするためにハッシュを使わないとかキーワード引数を使うなど気をつけた
      • 大きくなったときの書き方もつらみになりそうなのでモジュールへの切り出しなどなどをやっていく予定
    • みんな触ってqiitaとか書いてね!

僕はフロントエンドがからっきしなので興味がわく発表でした。フロントまでRubyで書けると大変助かる…!

つらみを減らして本来楽しいプログラミングを、という姿勢は大事にしていきたいですね。

State of Sorbet: A Type Checker for Ruby

Ruby 3では型チェックの導入が予定されており、型チェッカーとしてSorbetが導入されるそうです。 キャラクターが可愛いですね。

  • Sorbetで何をやるか
    • 静的型チェック
    • Uninitialized Constant ErrorやNo Method Errorを実行なしで捕まえる
    • もうStripeの本番で使ってる
  • demo
    • クラス名間違い
      • どこでエラーがあるのかを捕まえて表示できる
    • メソッド名間違い
      • 頭に「# typed: true」だけでエラーが捕まえられる
  • エラーを捕まえるだけじゃなくて引数を捕まえたり
    • 引数が受け付けられるかはメソッドの中見ないとわからないけど、頭におまじないを書くとSorbetが捕まえられる!
  • 早いのも良い点

多分みなさんdemoが見たいと思うので、こちらをどうぞ。 Sorbetの公式デモページで、VSCodeのSorbetプラグイン拡張をオンラインで体験できるようになっています。

Rubymineとかの高機能なIDEでやってるようなことをVSCodeのプラグインでできるようになってますね。

LT

一人5分の発表時間で12人の発表者が発表するセッションです。時間が過ぎると銅鑼がなって打ち切られます。

個々に解説するのは大変なので飛ばしますが、以下の2つは特に面白かったです。

  • Invitation to Dark Side of Ruby
    • macroを使った黒魔術。今回のLTで一番ウケていたと思います。
    • 直感的じゃないActiveRecordのORの書き方を where(x=1 || x=2) みたいな書き方にしてみた話
    • トークも実現していることも面白く、視聴おすすめです。
  • Applying mruby to World-first Small SAR Satellite
    • 人工衛星にmrubyを乗せた
    • 「リアルタイムgoogle map作りたい」「今のラーメン屋の行列見たい」というモチベーション
    • リアルタイムの経済的予測に使えるような衛星を想定している
    • 今年1基打ち上げる
    • 衛星の制約条件にmrubyがマッチする

動画が公開されたらぜひ見て下さい。