こんにちは、エムスリーキャリアでエンジニアをしているakitoshigaです。
前回書いた『Ruby on Railsのモジュラーモノリス化 ~PackwerkとPacksRailsの導入~ 』に関連する施策のひとつとして、静的型解析のSorbetとTapiocaを試験導入した話をご紹介します。
SorbetとTapiocaについて
Sorbetとは、Stripeが開発したRubyの静的(漸進的)型チェッカーです。
SorbetはRBIファイルとRubyファイルへの「sigil(s)」の記載によって機能するのですが、そのRBIファイルの作成をサポートするのがTapiocaです。
ちなみにTapiocaはShopify製になります。
なぜ導入したのか
弊社で保有するプロダクトの1つであるM3Career Primeではモジュラーモノリス化に取り組んでおり、この推進をするために導入したのが主な理由です。
具体的には以下の効果を見込んでいます。
型・インターフェースによるサポート
モジュラーモノリス化のためには当然ですがコードのモジュール化を行う必要があります。
M3Career Primeはいわゆる「巨大な泥団子」状態となっており、この状態からコードの境界を見極めAPIの定義・カプセル化を行っていくには型とインターフェースによるサポートが有効だと判断しました。
TechRachoさんの以下の記事にある『静的型が有効な場合とは』にそのまま当てはまる形です。
また、 インクリメンタルに導入が可能で途中からやめようと思えばやめられる点もあり今回導入に至りました。
現状の運用
まだ試験運用中ということもあり、TapiocaでRBIを自動生成した後は新規追加するAPIにsigilを随時定義しているような形で進めています。
既存のコードへの型定義は行っておりません。
また、Sorbetには適用する制約のレベルを段階的に設定できますが他チームメンバー内で相談して以下のようにしました。
- 制約レベルは `typed: true`
- パブリックなAPIには必ずsigilを記載
- 他の箇所は任意とする
ただしこのルールは暫定的なものでSorbetのもたらす恩恵が大きいと感じた場合はsigilの制約のレベルを強くするなど運用を変えていく可能性があります。
Steep(RBS)との比較
Sorbet以外の同じ型チェッカーで有名なSteepがありますが、以下の理由でSorbetを選択しました。
- Sorbetの方が型を制約するレベルを柔軟に設定できる。
- Sorbetはランタイムで型のチェックができる
SorbetとSteepの比較についてはWantedlyさんのテックブログで詳しくまとめてくださっています。
しかし、今後もずっとSorbetを使い続けるという保証はありません。
理由は以下で説明します。
Rubyの型の動向
以下でまつもとゆきひろさんが言及されているように、Rubyのそもそものコンセプトとして静的な型の定義は不要としています。
しかし、Rubyプログラマーの間で型に対する需要があるというのも事実で、そんな中で今年開催RubyKaigiでまつもとゆきひろさんが型について言及する場面がありました。
Matz「型は書きたくないというスタンスは変わらないが、コメントとして書く分には黙認する。近い未来ではIDEの中でショートカットをやるとRBSに書き込まれるというのが理想だが、それが難しいので現実的ソリューションとしてコメントで埋め込むのは黙認する」 #rubykaigi
— 黒曜@Leaner Technologies (@kokuyouwind) 2024年5月17日
またフルタイムRubyコミッターでSteepの開発者のsoutaroさんもコメントでRBSを定義できるGemを出していますね。
他にもaws-sdk-ruby配下のすべてのgemにRBSが含まれるようになったというニュースもあり、RBSはかなり盛り上がっているなと感じています。
まとめ
RBSを使用した型チェッカーに優位性があると判断した場合は、Steepや他の型チェッカーに移行する可能性もあるので今後の動向に注目していきたいと思います。