Slide 1

Slide 1 text

rbs-traceを使って WEARで型生成を試してみた 株式会社ZOZO
 ブランドソリューション開発本部 WEARバックエンド部 バックエンドブロック
 小山 慧 Copyright © ZOZO, Inc. 1 After RubyKaigi 2025〜ZOZO、ファインディ、ピクシブ〜

Slide 2

Slide 2 text

© ZOZO, Inc. 株式会社ZOZO ブランドソリューション開発本部 WEARバックエンド部 バックエンドブロック 小山 慧 ● 2019年4月 株式会社ZOZOに新卒入社 ○ WEARのバックエンド開発を担当 ○ RubyKaigiは今年4回目! 2

Slide 3

Slide 3 text

© ZOZO, Inc. https://wear.jp/ 3 ● あなたの「似合う」が探せるファッションコーディネートアプリ ● 1,800万ダウンロード突破、コーディネート投稿総数は1,400万 件以上(2024年12月末時点) ● コーディネートや最新トレンド、メイクなど豊富なファッション 情報をチェック ● AIを活用したファッションジャンル診断や、フルメイクをARで試 せる「WEARお試しメイク」を提供 ● コーディネート着用アイテムを公式サイトで購入可能 ● WEAR公認の人気ユーザーをWEARISTAと認定。モデル・タレン ト・デザイナー・インフルエンサーといった各界著名人も参加

Slide 4

Slide 4 text

© ZOZO, Inc. 4 RubyKaigi今年も最高でした!!!

Slide 5

Slide 5 text

© ZOZO, Inc. 5 スポンサーブースやお昼ご飯が豪華!

Slide 6

Slide 6 text

© ZOZO, Inc. 6 ドリンクアップなどを通じて社内外の方々と交流もできました! ● 社外の人とたくさん話せました! ○ @Findy Drinkup at RubyKaigi 2025 ○ ドリンクアップで知り合った方々とランチも ● 社内の交流も深まりました! ○ みかんジュース飲み比べ ○ 松山城観光

Slide 7

Slide 7 text

© ZOZO, Inc. 今回のテーマは「型」 RubyKaigi 2025を機にRubyの型に入門した初心者です

Slide 8

Slide 8 text

© ZOZO, Inc. 8 今日話す内容 ● RBSとrbs-traceについて ● rbs-traceを試してみたいと思った背景 ● rbs-traceをWEARで試してみた

Slide 9

Slide 9 text

© ZOZO, Inc. 9 RBSとは ● Rubyのプログラムの型情報を記述するための言語 ● Ruby 3.0から標準ライブラリとして同梱されている ● 型定義は.rbsファイルとして、.rbファイルから独立して管理される ○ 型情報を記述することで、動的型付け言語であるRubyの柔軟性を維持しつつ、静 的型チェックの恩恵を得られる

Slide 10

Slide 10 text

© ZOZO, Inc. 10 RBSの記述方法 ● 型定義専用の.rbsファイルに記述する方法 ● rbs-inlineというgemを用いて、.rbファイル内のコメントとして型定義を記述する方法 ○ YARDのような形式 ○ rbs-inlineコマンドで、.rbsファイルが生成できる ○ 将来的にはrbs gemにマージされる予定

Slide 11

Slide 11 text

© 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

Slide 12

Slide 12 text

© 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

Slide 13

Slide 13 text

© ZOZO, Inc. 13 rbs-traceとは ● Rubyの標準ライブラリであるTracePointを活用して、テスト実行時に型情報を収集 ● .rbファイル内にrbs-inline用の埋め込み型の型宣言として自動的に挿入してくれる ● .rbsファイルも自動的に生成してくれる

Slide 14

Slide 14 text

© 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ではテストコードを書く文化が根付いているので親和性が高いと感じたため

Slide 15

Slide 15 text

© ZOZO, Inc. rbs-traceをWEARで試してみた

Slide 16

Slide 16 text

© 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

Slide 17

Slide 17 text

© 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

Slide 18

Slide 18 text

© 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

Slide 19

Slide 19 text

© ZOZO, Inc. 必要な準備はこれだけ!

Slide 20

Slide 20 text

© ZOZO, Inc. 20 RSpec実行 ● bundle exec rspec spec/models/coordinate_spec.rb

Slide 21

Slide 21 text

© ZOZO, Inc. 21 出力結果を確認 ● app/models/coordinate.rb にインラインコメントで @rbs のシグネチャが付与された ● sig/trace/app/models/coordinate.rbs が生成されて、RSpecから呼び出された対象の クラスとメソッドの型が生成された ● 107個あるメソッドのうち79個に対して型が付いた! ○ テスト時に実行されさえすればprivateメソッドであっても型情報が生成された

Slide 22

Slide 22 text

© ZOZO, Inc. 22 rbs-traceを実運用する上での課題 ● テスト内で実行されないメソッドには型が付かない ● ArrayやHashといったコレクションオブジェクトの中身はuntypedで定義される ● 型が正しく定義されているかの確認が大変 ○ WEARのRailsアプリにはYARDが既に記述されているので、今回はYARDと見比べ て確認をした ● テスト実行の度に.rbsファイルはすべて新しく作り直される ● .rbファイルのメソッドの引数や戻り値を変更した後にテストを実行した場合であって も.rbファイル内のインラインRBSコメントが更新されない ○ .rbsファイルと.rbファイル内のインラインRBSコメントの型とで乖離が起こる

Slide 23

Slide 23 text

© ZOZO, Inc. 23 VS Code拡張のSteepを導入

Slide 24

Slide 24 text

© ZOZO, Inc. 24 Steepとは ● Rubyプログラムの静的な型検査を行うためのgem ● LSPの機能も内包しており、SteepのLSPサーバーは.rbsファイルに記述された型情報 と、.rbファイルの実際のRubyコードを照らし合わせることでエディタに対して以下の ような機能を提供する ○ コード補完 ○ エラーハイライト ○ 型情報の表示 ○ 定義ジャンプ

Slide 25

Slide 25 text

© ZOZO, Inc. 25 Steepの導入 1. steep をGemfileへ追加 2. bundle install 3. bundle exec steep init を実行してSteepfileを生成

Slide 26

Slide 26 text

© ZOZO, Inc. 26 steep check実行前の準備 1. rbs collection init を実行 2. rbs collection install を実行してgemのRBSシグネチャを取得してくる 3. Steepfileに次のページの設定を記述

Slide 27

Slide 27 text

© 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

Slide 28

Slide 28 text

© ZOZO, Inc. 28 steep check実行 ● bundle exec steep check を実行して静的型検査を行う

Slide 29

Slide 29 text

© ZOZO, Inc. 29 steep checkの結果を確認 ● rbs_collectionに存在しないgemの型定義や、今回はrbs-traceで1つの.rbsファイルし か生成していない関係で他の自作クラスの型定義がないため、Cannot find typeエ ラーが発生した ● Cannot find typeエラーに対しては、今回は、steep checkを通すため全てuntypedに 置き換えることで対応した

Slide 30

Slide 30 text

© ZOZO, Inc. 30 steep checkを再度実行 ● 無事にNo type error detected.になった!

Slide 31

Slide 31 text

© ZOZO, Inc. 31 LSPの恩恵を受けることができた(コード補完)

Slide 32

Slide 32 text

© ZOZO, Inc. 32 LSPの恩恵を受けることができた(エラーハイライト)

Slide 33

Slide 33 text

© ZOZO, Inc. 33 Steepによる静的型検査で型安全を担保 ● Ruby.silentでの実行のため未達成 ● 先述の通り、Ruby.silentであったとしても、Cannot find typeエラーは発生する ● 存在しない型定義についてはuntypedを明示してエラーを避けるか、自前でシグネ チャを記述するなどの対応が必要なため、Steepで型検査を行うのは実際の運用を考え ると手間がかかりそう ● untypedが多くなってしまうと型安全性は弱くなる

Slide 34

Slide 34 text

© ZOZO, Inc. 34 今後試してみたいこと ● rbs-traceで初回の型付けを実行した後にrbs-inlineを使って型定義を運用していくと いうイメージが付いたので、実践してみたい ● Ruby.silentではなくRuby.lenientなどを使い段階的に型安全性を高めたい ● 今回は試せなかったが、WEARはyardを書く文化もあるので、yardから型生成してく れるsordというgemも試してみたい

Slide 35

Slide 35 text

© ZOZO, Inc. 35 RubyKaigiを振り返って ● SorbetがRBSファイルのパースに取り組んでいたり、rbs-inlineがrbsの標準になる動 きがあるなど、型周りのエコシステムが統合されつつある印象でした! ● RBS周りは進化が早いので今後も動向を追っていきたいです!

Slide 36

Slide 36 text

No content