Upgrade to Pro — share decks privately, control downloads, hide ads and more …

rbs-traceを使ってWEARで型生成を試してみた After RubyKaigi 202...

rbs-traceを使ってWEARで型生成を試してみた After RubyKaigi 2025〜ZOZO、ファインディ、ピクシブ〜 / tried rbs-trace on WEAR

Avatar for Kei Oyama

Kei Oyama

May 16, 2025
Tweet

Other Decks in Programming

Transcript

  1. © ZOZO, Inc. 株式会社ZOZO ブランドソリューション開発本部 WEARバックエンド部 バックエンドブロック 小山 慧 •

    2019年4月 株式会社ZOZOに新卒入社 ◦ WEARのバックエンド開発を担当 ◦ RubyKaigiは今年4回目! 2
  2. © ZOZO, Inc. https://wear.jp/ 3 • あなたの「似合う」が探せるファッションコーディネートアプリ • 1,800万ダウンロード突破、コーディネート投稿総数は1,400万 件以上(2024年12月末時点)

    • コーディネートや最新トレンド、メイクなど豊富なファッション 情報をチェック • AIを活用したファッションジャンル診断や、フルメイクをARで試 せる「WEARお試しメイク」を提供 • コーディネート着用アイテムを公式サイトで購入可能 • WEAR公認の人気ユーザーをWEARISTAと認定。モデル・タレン ト・デザイナー・インフルエンサーといった各界著名人も参加
  3. © ZOZO, Inc. 6 ドリンクアップなどを通じて社内外の方々と交流もできました! • 社外の人とたくさん話せました! ◦ @Findy Drinkup

    at RubyKaigi 2025 ◦ ドリンクアップで知り合った方々とランチも • 社内の交流も深まりました! ◦ みかんジュース飲み比べ ◦ 松山城観光
  4. © ZOZO, Inc. 9 RBSとは • Rubyのプログラムの型情報を記述するための言語 • Ruby 3.0から標準ライブラリとして同梱されている

    • 型定義は.rbsファイルとして、.rbファイルから独立して管理される ◦ 型情報を記述することで、動的型付け言語であるRubyの柔軟性を維持しつつ、静 的型チェックの恩恵を得られる
  5. © ZOZO, Inc. 10 RBSの記述方法 • 型定義専用の.rbsファイルに記述する方法 • rbs-inlineというgemを用いて、.rbファイル内のコメントとして型定義を記述する方法 ◦

    YARDのような形式 ◦ rbs-inlineコマンドで、.rbsファイルが生成できる ◦ 将来的にはrbs gemにマージされる予定
  6. © ZOZO, Inc. 11 rbs-inlineの埋め込み型の型宣言がされた.rbファイル 引用元:https://github.com/soutaro/rbs-inline .rbファイル # rbs_inline: enabled

    class Person attr_reader :name #: String attr_reader :addresses #: Array[String] # @rbs name: String # @rbs addresses: Array[String] # @rbs return: void def initialize(name:, addresses:) @name = name @addresses = addresses end # @rbs () -> String def to_s "Person(name = #{name}, addresses = #{addresses.join(", ")})" end end
  7. © ZOZO, Inc. 12 rbs-inlineから生成される.rbsファイル 引用元:https://github.com/soutaro/rbs-inline .rbsファイル class Person attr_reader

    name: String attr_reader addresses: Array[String] def initialize: (name: String, addresses: Array[String]) -> void def to_s: () -> String end
  8. © ZOZO, Inc. 14 rbs-traceを試してみたいと思った背景 • 例年、RBS関連のセッションが多く、注目が集まっているため • 型の恩恵を感じてみたかったため ◦

    LSPによる開発体験の向上 ◦ Steepによる静的型検査で型安全を担保出来ること • Rubyで型を自動生成するアプローチが様々登場してきている中で、その1つを試してみたかったた め ◦ rbs-trace ◦ rbs prototype ◦ rbs-inline ◦ rbs_rails ◦ orthoses ◦ sord ◦ Tapioca & Spoom ◦ RBS Goose ◦ etc. • WEARではテストコードを書く文化が根付いているので親和性が高いと感じたため
  9. © ZOZO, Inc. 16 環境 • ruby: 3.3.6 • Rails:

    6.1.7.10 • rbs: 3.9.2 • rbs-trace: 0.51 • steep: 1.10.0 • VS Code: 1.99.3
  10. © ZOZO, Inc. 17 rbs-traceの導入方法 1. rbs-trace をGemfileへ追加 2. bundle

    install 3. RSpecに統合するため spec/support/rbs_trace.rb を作成して次のページのコードを 追加 a. 今回はLSPの恩恵を得るためにsteep checkも通したかったので、対象を app/models/coordinate.rb に絞った 引用元:https://github.com/sinsoku/rbs-trace
  11. © ZOZO, Inc. 18 rbs-traceの導入方法 RSpec.configure do |config| # RBSの出力対象とするファイルを指定

    trace = RBS::Trace.new(paths: Dir.glob("#{Dir.pwd}/app/models/coordinate.rb")) config.before(:suite) { trace.enable } config.after(:suite) do trace.disable trace.save_comments # RBSファイルの格納先を指定 trace.save_files(out_dir: "sig/trace/") end end
  12. © ZOZO, Inc. 21 出力結果を確認 • app/models/coordinate.rb にインラインコメントで @rbs のシグネチャが付与された

    • sig/trace/app/models/coordinate.rbs が生成されて、RSpecから呼び出された対象の クラスとメソッドの型が生成された • 107個あるメソッドのうち79個に対して型が付いた! ◦ テスト時に実行されさえすればprivateメソッドであっても型情報が生成された
  13. © ZOZO, Inc. 22 rbs-traceを実運用する上での課題 • テスト内で実行されないメソッドには型が付かない • ArrayやHashといったコレクションオブジェクトの中身はuntypedで定義される •

    型が正しく定義されているかの確認が大変 ◦ WEARのRailsアプリにはYARDが既に記述されているので、今回はYARDと見比べ て確認をした • テスト実行の度に.rbsファイルはすべて新しく作り直される • .rbファイルのメソッドの引数や戻り値を変更した後にテストを実行した場合であって も.rbファイル内のインラインRBSコメントが更新されない ◦ .rbsファイルと.rbファイル内のインラインRBSコメントの型とで乖離が起こる
  14. © ZOZO, Inc. 25 Steepの導入 1. steep をGemfileへ追加 2. bundle

    install 3. bundle exec steep init を実行してSteepfileを生成
  15. © ZOZO, Inc. 26 steep check実行前の準備 1. rbs collection init

    を実行 2. rbs collection install を実行してgemのRBSシグネチャを取得してくる 3. Steepfileに次のページの設定を記述
  16. © ZOZO, Inc. 27 Steepfile D = Steep::Diagnostic target :app

    do # RBSファイルの格納先を指定 signature "sig/trace/app/models/coordinate.rbs" # Steepで型チェックする対象のファイルを指定 check "app/models/coordinate.rb" configure_code_diagnostics(D::Ruby.silent) end 引用元:https://github.com/soutaro/steep/blob/v1.10.0/manual/ruby-diagnostics.md
  17. © ZOZO, Inc. 28 steep check実行 • bundle exec steep

    check を実行して静的型検査を行う
  18. © ZOZO, Inc. 29 steep checkの結果を確認 • rbs_collectionに存在しないgemの型定義や、今回はrbs-traceで1つの.rbsファイルし か生成していない関係で他の自作クラスの型定義がないため、Cannot find

    typeエ ラーが発生した • Cannot find typeエラーに対しては、今回は、steep checkを通すため全てuntypedに 置き換えることで対応した
  19. © ZOZO, Inc. 33 Steepによる静的型検査で型安全を担保 • Ruby.silentでの実行のため未達成 • 先述の通り、Ruby.silentであったとしても、Cannot find

    typeエラーは発生する • 存在しない型定義についてはuntypedを明示してエラーを避けるか、自前でシグネ チャを記述するなどの対応が必要なため、Steepで型検査を行うのは実際の運用を考え ると手間がかかりそう • untypedが多くなってしまうと型安全性は弱くなる