初めまして、ENECHANGEで働いている id:tetsushi_fukabori です。
本ブログには初登場になります。これからよろしくお願いします。
本記事で書くこと
「私がRubyKaigi 2019に参加して感じたこと」「私が参加したセッションで話されたことの要約と感想」を主に書きます。
RubyKaigiはYouTubeチャンネルがあるので、講演を全て観たい方はこちらもどうぞ(本記事執筆時点ではまだ2019年分はアップされていません)。
(なお、ENECHANGEからは私と id:cuzic の2名が参加しており、重複して参加したkeynoteについては id:cuzic がまとめていますのでこちらをご覧ください)
RubyKaigi初参加の私が感じたこと
RubyKaigiはRubyコミュニティでは世界最大のカンファレンスで年に一回開催されます。 私がRubyKaigiの存在を知ったのは5-6年前のことでしたが、めぐり合わせもありこれまで参加できていませんでした。
今回初参加して何より感じましたが、このカンファレンスはやたらと居心地が良いですね。 運営の皆さん、登壇者の皆さん、スポンサーブースの皆さんも、何より参加者の全員から「イベントを楽しもう、イベントを楽しいものにしよう」という気持ちが強く感じられます。
Ruby本やRuby技術同人誌の見本が大量にならんでいて感想の付箋がついていたり、毎日コードクイズが出題されていたり、Ruby製のファッションチェックアプリで遊べたりとみんなでRubyで遊んでいる雰囲気でした。
参加者のスキル感やコミュニティーへの参加具合などは(多分)様々ですが、「Rubyチョットデキル」な強い人だけでなく参加者全員が「Rubyは楽しいなぁ」と感じられる場所なので、未参加の方はぜひ参加してみてください。
本文に入る前に:RubyGems.orgの多要素認証を設定しましょうのお知らせ
RubyKaigi 2019でRubyコミッターが発表する前には必ずアナウンスされていた重要事項ですのでここでもお知らせです。
- RubyGems.orgのアカウントに対して攻撃が行われている
- 攻撃防止のため、現時点でRubyGems.orgのアカウントを持っている方、これからRubyGems.orgのアカウントを作成される方は必ず多要素認証(MFA: Multi-Factor Authentication)を設定してください
- 実際にbootstrap-sass gemへの攻撃が行われ、version 3.2.0.3に攻撃のコードが含まれていました
みなさんでコミュニティを守っていきましょう!
Day 1のセッション
How to use OpenAPI3 for API developer
どちらかというとOpenAPI2までのSwaggerという名前の方が通りがいいかもしれません。OpenAPI3自体は少し前のWEB+DB PRESSでも特集されてましたね。
OpenAPI3でのAPI開発と、その中で使われるgemを直したよ、という発表でした。
- OpenAPI 3
- 大量のAPIがある、大人数でのアプリ-サーバ間API開発においてスキーマ駆動のAPI開発を進めるためよく使われる
- 普通にAPIの開発を進めるとアプリ側はサーバーサイドの実装を待って(もしくは取り決めたことを正として)アプリ側が開発を進める →大体の場合認識齟齬や実装ミスがありがちなので、結合時点でバグりやすい
- なので、APIインターフェース(スキーマ)を先に機械的に定義し、サーバサイドもアプリサイドも定義に沿って開発を進めること →開発速度だったり結合時のエラー削減だったりができる(スキーマ駆動開発)
- OpenAPIを使うとスキーマの定義だったりモックだったりドキュメントだったりを作成できる
- OpenAPI3はあくまで定義
- OPEN APIはあくまで定義なので、実装との一致は保証してくれない
- 定義のチェックツールが必要になる → committee gem
- committee
- アプリとクライアントの間に立ってエラー返してくれたり
- リクエストを定義に沿って変換したりしてくれる
- committeeの実装
- committeeはOpenAPIには直接的には対応できておらず、同じくスキーマ定義のJSON Hyperschemaに対してのみだった(OpenAPI2(Swagger)にも使えるが、OpenAPI2をHyperschemaに変換して適用している)
- committeeはJSON Hypershemaと結合が強い→ちゃんとOpenAPI3を解釈するように変更したい
- ので、JSON HyperschemaやOpenAPI3それぞれのパーサークラスを作って、committeeはそれに依存するように作り変えた!
以降はどのようにパーサーを実装したかの話でした。
OpenAPI3自体は知っていましたがcommitteeは知りませんでした。 さらに「依存が強いから書き直そう」という発想が実にRubyistらしいやり方だなぁ、という感じ。 資料には「構造がこうなっているからここに手を加えることで依存が剥がせると考えた」という解説があり、どちらかというと密結合なプログラムのリファクタリングの話として聞いていました。
Pragmatic Monadic Programing in Ruby
モナド をrubyに実装しよう、という試みの発表。 gemの形まで持っていったようです。
Ruby2.6からRubyVM::AST (Abstract Syntax Tree:抽象構文木)というモジュールが導入され、Rubyの黒魔術を使う界隈では結構ホットな話らしいです。 正直にいうと全然理解が追いつかず、無念です。
モナド自体は関数型プログラミングで使われる「使いやすいデザインパターンの一つ」、ということだそうで、紹介されたgemを使ってみると普段のRubyでは書けない(書かない)ようなコードが書けて楽しいかもしれません。
なお、発表者曰く「(現段階では)このgemをproductionで使うことはオススメしません!」だそうです。
Ruby for NLP
RubyでNLP(Natural Language Processing:自然言語処理)をやろう、という発表。 発表時間の多くをNLPの解析的手法の説明に割いていたので聞いていて分かりやすく興味を持てました。
NLPの手法の解説をここで書き連ねても何なので発表の趣旨に当たる部分を書きます。
- NLP = MeCabとかNLP = Pythonみたいに言われるけど、そんなことはない
- Ruby for NLP
- Natto, jumanpp_rubyなどのNLP用のgemがある
- だいたいCとかのライブラリをバインドしてるので結構早い
- RubyでNLPをやりたい
- Red Data ToolsプロジェクトでRubyでNLPに必要なツールなどを開発している
- 例えばPythonのChainerをRubyに移植したRed Chainerなんてのもある
- Red Data ToolsプロジェクトでRubyでNLPに必要なツールなどを開発している
- RubyでNLPをやる人が少ない
- みんなpythonとかってなっちゃうと、ますます人がいなくなっちゃう
- なので、みなさんぜひRubyで自然言語処理をやってみてください
- Natto, jumanpp_rubyなどのNLP用のgemがある
確かに、自然言語のデファクトスタンダードがPythonという認識が強まれば強まるほどRuby界隈ではその領域をやれる人が減りコミュニティが盛り下がり…となっちゃいますね。
Ruby自体は手段ですが、楽しくプログラムを書ける手段なので、Rubyが好きな方は自然言語処理をしたくなったらRed Data Toolsをみてみると良いですね!
なお、発表者の方は技術書典で「猫と森羅と日本語とRuby」というRubyでNLPをする薄い本を執筆されています。 (RubyKaigiでも発表後に販売されていたので僕も買いました。)
A Bundle of Joy: Rewriting for Performance
bundlerが遅いから高速化してGelというgemにした、という発表。
この発表は凄かったです。 依存関係解消の効率化などなど手法は様々ですが、「一部機能に特化し、bundlerと互換性のあるツール」として非常に優秀なパフォーマンスを実現していました。
- Gelは…
- bundle install/update/lock/execをサポートしてる。他の機能は対象外。
- bundleと同じように gel install、gel update などの使用方法で使える
- bundle より早い
- いくつかデモを見せてもらいましたが、bundlerに比べてだいたい半分の時間で同じことができていました
デモではbundlerで実行した場合→gelで実行した場合の順で同じ処理を行なっていたのですが、bundlerの方を「あー…こんな感じで待つよねー……」とみていたら、そのあとのGelの速さに思わず呻きました。
実際普段の開発でbundlerの全機能が必要になることは少ないですし、bundler互換なので通常はgel&必要な時はbundlerとすることで大きな恩恵が得られそうです。 デプロイ時間の短縮化や環境構築周りで恩恵が大きそうですね。
Pattern matching - New feature in Ruby 2.7
Ruby2.7から導入のパターンマッチングのイントロダクションです。
case ~ when ではなくcase ~ in でパターンマッチして処理分岐できるようになりました。
サンプルをみた方が分かりやすいのでいくつかサンプルを発表資料から引用させて頂くと
case [0, [1, 2, 3]] in [a, [b, *c]] p a #=> 0 p b #=> 1 p c #=> [2, 3] end
とか、JSON形式の入力
{ "name": "Alice", "age": 30, "children": [ { "name": "Bob", "age": 2 } ] }
に対して
case JSON.parse(json, symbolize_names: true) in {name: "Alice", children: [{ name: "Bob", age: age }]} p age #=> 2 end
みたいな受け方ができます。Arrayのindexを書かないで済んだり便利!
- 条件に変数を設定できる
- ユースケース:JSONをパースして想定のデータ形式であれば処理に入れる、など
- 文法
- どれにも該当しなくてelseもないと例外を起こす
- inのパターン文の後ろにifとかunlessでガード条件をかける
- 評価順はパターン一致評価→ガード評価→ガードを通ったら中の処理を評価
- パターン
- value pattern
- case whenと同じ(pattern === object)
- valiable pattern
- caseの値を変数に代入して使う
[_, _]
とか使えるのでフォーマットだけ確認とかもできる- case ~ inの前に同名変数がすでに存在すると? →普通に使うと上書きされる
- 既存の変数をinのパターンの中で使いたい場合があるはずなので、その場合は変数の前に「^」つけると上書きされず使える
- alternative pattern
- as pattern
- マッチして成功したら右辺に代入
- rescueみたいなイメージで
in Integer => x
みたいに使える - 複雑なパターンにも便利(…ですが、読みやすさはやや低そうに感じました)
- array pattern
- 命名はarrayだけどarrayのためだけに使われる訳ではない
- クラスにArrayを返す
deconstruct
メソッドが実装されていれば、それを使ってArrayにして比較を行う
- hash pattern
- 命名はhashだけど(ry
- ほぼarray pattern
- Hashを返す
deconstruct_keys
メソッドを使う - inにkeyだけ書いてマッチするとkeyと同名変数にvalueを代入できる(これは便利感ある!読みやすそう!)
- keysを指定することで早くできる
- が、keys指定で早くなることもあればそうでないこともある。よく考えて使ってください、とのこと。
- value pattern
- 機能のデザイン
- 考えていたこと
- 新しい予約語は作らない、既存コードを守る
- じゃあwhenじゃなくて何を使えば読みやすいか?
- 「なんとrubyには
for
がある!」 - forで使えるinを流用することで既存を壊さず自然な書き方ができる
- 新しい名前空間も作らない
- rubyらしくあれ
- 強力なArrayとHashのサポート
- ArrayとHashで厳密マッチかサブセットマッチかを変えてる
- 空のハッシュをパターンにしたらどうなる?→全部のhashにマッチしちゃう
- matzの鶴の一声でからハッシュにマッチするようにした
- ダックタイピングを推奨する
- 強力なArrayとHashのサポート
- 新しい予約語は作らない、既存コードを守る
- 考えていたこと
- trunkのコードを試そうね。フィードバックくださいね。
結構パワフルな機能追加ですね。
必要ならclassの deconstruct
/ deconstruct_keys
を実装しちゃえば強力なパターンマッチの恩恵が得られるのも簡単で良いなと。
今までcase ~ whenでは ===
での一致でしたが、 ===
やその再定義では書きにくいパターンマッチを実現しやすいかと!
trunkというのはrubyの開発ブランチです。trunkは一番進んでいるブランチで安定版はtrunkから切り出されます。 Rubyコミュニティでは新しいコードをいじって突っ込んでくれる人を常に求めているので、みなさん触ってみましょう!