omakaseしないための.rubocop.yml のつくりかた / How to Build Your .rubocop.yml to Avoid Omakase #kaigionrails
by
Linkers Tech
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
omakaseしないための .rubocop.yml のつくりかた 2024/10/26 Kaigi on Rails 2024 Shu Oogawara(@expajp) 1
Slide 2
Slide 2 text
• Shu Oogawara(@expajp ) • Engineering Manager@リンカーズ • Engineering Manager Meetup コアスタッフ • 趣味 • 秘境駅めぐり • 深夜ラジオ • 筋トレ 2 自己紹介
Slide 3
Slide 3 text
みなさん、RuboCop使ってますか? 3 画像引用:“rubocop/rubocop: A Ruby static code analyzer and formatter, based on the community Ruby style guide.”, https://github.com/rubocop/rubocop, 2024/10/06閲覧
Slide 4
Slide 4 text
• Ruby向けの静的コードアナライザ・フォーマッタ • 個別のルールを”Cop” と呼ぶ • .rubocop.yml でCopごとの有効/無効やオプション設定が可能 4 コードにルールを設け、それを強制するツール
Slide 5
Slide 5 text
• 危険を避ける • 不具合を予防する • ベストプラクティスを強制する • コードベースの保守性を高める • 一貫性を保証する • 無用な議論を避ける 5 なぜコードにルールを設けるのか 画像引用:オライリー・ジャパン, ” Googleのソフトウェアエンジニアリング”, https://www.oreilly.co.jp/books/9784873119656/, 2024/10/06閲覧
Slide 6
Slide 6 text
# bad open(something) open("| #{something}") open("| foo") URI.open(something) # good File.open(something) IO.popen(something) URI.parse(something).open # good (literal strings) open("foo.text") URI.open("http://example.com") • コマンドインジェクション 脆弱性を防ぐ • Kernel#open に変数などを 渡していたら検出する 6 目的別のCopの例 危険を避ける:Security/Open 引用:”Security :: RuboCop Docs”, https://docs.rubocop.org/rubocop/cops_security.html#securityopen, 2024/10/21閲覧
Slide 7
Slide 7 text
• *(アスタリスク)が 乗算か配列展開か ひと目で分からない 書き方を検出する 7 目的別のCopの例 ベストプラクティスを強制:Lint/AmbiguousOperator # bad # (中略) do_something *some_array # good # (中略) do_something(*some_array) 引用:”Lint :: RuboCop Docs”, https://docs.rubocop.org/rubocop/cops_lint.html#lintambiguousoperator, 2024/10/21閲覧
Slide 8
Slide 8 text
• {}(波括弧)内側の スペースの有無を検出 • ありなしどちらを正とするかは 設定次第 8 目的別のCopの例 一貫性を保証:Layout/SpaceInsideBlockBraces # bad some_array.each {puts e} # good some_array.each { puts e } 引用:”Layout :: RuboCop Docs”, https://docs.rubocop.org/rubocop/cops_layout.html#layoutspaceinsideblockbraces, 2024/10/21閲覧
Slide 9
Slide 9 text
コードにルールを設けることは利益がある 9
Slide 10
Slide 10 text
10 しかし、既存のコードベースにRuboCopを導入するのは大変 大量の警告 コンフリクト地獄 サードパーティ プリセットいっぱいありすぎ 僕は気にしないんで 勝手にやってください 時間を使いたくない 好みの問題でしょ 圧倒的物量 開発遅れるなら やめてもらえますか そんなことより ここの実装なんですけど これを無効に するなんて ありえない いくつに設定するのが 正しいんでしょうねえ 自転車置き場
Slide 11
Slide 11 text
11 しかし、既存のコードベースにRuboCopを導入するのは大変 大量の警告 コンフリクト地獄 サードパーティ プリセットいっぱいありすぎ 僕は気にしないんで 勝手にやってください 時間を使いたくない 好みの問題でしょ 圧倒的物量 開発遅れるなら やめてもらえますか そんなことより ここの実装なんですけど これを無効に するなんて ありえない いくつに設定するのが 正しいんでしょうねえ 自転車置き場 設定が先延ばしにされがち
Slide 12
Slide 12 text
12 最近の話題 Rails 7.2 から RuboCopがデフォルトで導入されるようになった RuboCopの設定にもレールを敷いてくれるのでは?
Slide 13
Slide 13 text
13 Issue 画像引用:” Add (a very basic!!) Rubocop by default · Issue #50456 · rails/rails · GitHub”, https://github.com/rails/rails/issues/50456, 2024/10/06閲覧
Slide 14
Slide 14 text
14 Blog 画像引用:”A writer's Ruby”, https://world.hey.com/dhh/a-writer-s-ruby-2050b634, 2024/10/06閲覧
Slide 15
Slide 15 text
RuboCopは”自分たちの”スタイルを一貫させる ツールとして素晴らしい スタイルをまだ見つけてないチームのため omakaseのメニューを用意したので出発点にしてほしい 15 Blogの要約(発表者による) 画像引用:” dhh (David Heinemeier Hansson)”, https://github.com/dhh, 2024/10/06閲覧
Slide 16
Slide 16 text
• rubocop-rails-omakase • 7.2以降で `rails new` するとデフォルトで入るgem • 有効に設定されているCopはわずか46個 • 参考:拡張なしRuboCopに含まれるCopは554個(RuboCop 1.67) • Layout: 27 / Style: 12 / Lint: 3 / Performance: 2 / Rails: 2 • 他のCopはすべて無効になっている 16 出発点としてのomakase ほぼ「一貫性を保証する」役割しか担っていない
Slide 17
Slide 17 text
omakaseは銀の弾丸にあらず やっぱり自分たちのスタイルを見つけなくてはならない 17
Slide 18
Slide 18 text
omakaseは銀の弾丸にあらず やっぱり自分たちのスタイルを見つけなくてはならない 18 前述の通り、簡単には見つけられない
Slide 19
Slide 19 text
omakaseは銀の弾丸にあらず やっぱり自分たちのスタイルを見つけなくてはならない 19 しかし、これを話し合って決めるのは簡単ではない 一方で
Slide 20
Slide 20 text
我々のチームは9ヶ月かけて話し合い 自分たちの.rubocop.yml をつくることに成功した 20
Slide 21
Slide 21 text
当初の.rubocop_todo.yml 21 • 501行 • 59Copを無視 • 6275箇所の違反
Slide 22
Slide 22 text
22 9ヶ月後
Slide 23
Slide 23 text
23 今日の話 既存のコードベースにRuboCopを導入したとき 設定をどう決めていくか?
Slide 24
Slide 24 text
• .rubocop.yml をつくる難しさを知り克服する • .rubocop.yml のつくりかたを実践する • 成功の要因を深堀りする 24 Agenda
Slide 25
Slide 25 text
.rubocop.yml を つくる難しさを知り克服する
Slide 26
Slide 26 text
Q. そもそも.rubocop.yml をつくるのはなぜ難しいか? 26
Slide 27
Slide 27 text
• 直接は売上を生まないから • チームの文化を言語化・集約したものだから 27 Q. そもそも.rubocop.yml をつくるのはなぜ難しいか?
Slide 28
Slide 28 text
• 直接は売上を生まないから • チームの文化を言語化・集約したものだから 28 Q. そもそも.rubocop.yml をつくるのはなぜ難しいか?
Slide 29
Slide 29 text
29 文化 人間の生活様式の全体。(中略) それぞれの民族・地域・社会に固有の文化があり、 学習によって伝習されるとともに、 相互の交流によって発展してきた。 “ “文化(ブンカ)とは? 意味や使い方 - コトバンク”, https://kotobank.jp/word/%E6%96%87%E5%8C%96-128305, 2024/10/22閲覧
Slide 30
Slide 30 text
RuboCopは”自分たちの”スタイルを一貫させる ツールとして素晴らしい スタイルをまだ見つけてないチームのため omakaseのメニューを用意したので出発点にしてほしい 30 Blogの要約(発表者による) 画像引用:” dhh (David Heinemeier Hansson)”, https://github.com/dhh, 2024/10/06閲覧 再掲
Slide 31
Slide 31 text
RuboCopは”自分たちの”スタイルを一貫させる ツールとして素晴らしい スタイルをまだ見つけてないチームのため omakaseのメニューを用意したので出発点にしてほしい 31 Blogの要約(発表者による) 画像引用:” dhh (David Heinemeier Hansson)”, https://github.com/dhh, 2024/10/06閲覧 再掲 スタイル≒生活様式≒文化
Slide 32
Slide 32 text
• 直接は売上を生まないから • チームの文化を言語化・集約したものだから 32 Q. そもそも.rubocop.yml をつくるのはなぜ難しいか? 生活様式を言語化し チームで統一する作業が 簡単なはずはない
Slide 33
Slide 33 text
• 売上を生まない 33 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約
Slide 34
Slide 34 text
• 売上を生まない 34 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい
Slide 35
Slide 35 text
• 売上を生まない 35 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい
Slide 36
Slide 36 text
• 売上を生まない 36 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい これらを克服する必要がある
Slide 37
Slide 37 text
• 売上を生まない 37 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい
Slide 38
Slide 38 text
• 売上を生まない 38 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい
Slide 39
Slide 39 text
39 どこで時間を取るか? すでに定期開催されているMTGの中
Slide 40
Slide 40 text
40 定期MTGの中に時間を確保する なぜ時間の確保が難しいか? •売上を生む開発を妨げるから
Slide 41
Slide 41 text
41 定期MTGの中に時間を確保する なぜ時間の確保が難しいか? •売上を生む開発を妨げるから 逆に、開発を妨げなければ時間を取って良い
Slide 42
Slide 42 text
• 一度にたくさん取らず、少しずつ取る • スケジュールが想定する可処分時間を圧迫しない • 他の会議と連続して取る • 開発メンバーが集中しているのを中断しない 42 定期MTGの中に時間を確保する 開発を妨げない時間の取り方
Slide 43
Slide 43 text
• 一度にたくさん取らず、少しずつ取る • スケジュールが想定する可処分時間を圧迫しない • 他の会議と連続して取る • 開発メンバーが集中しているのを中断しない 43 定期MTGの中に時間を確保する 開発を妨げない時間の取り方 両方を満たすのが「定期MTGの中」
Slide 44
Slide 44 text
• 売上を生まない 44 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい
Slide 45
Slide 45 text
• 売上を生まない 45 Q. .rubocop.yml をつくるのは何が難しいか? • 文化の言語化・集約 時間の確保が難しい ファシリテーション が難しい
Slide 46
Slide 46 text
• 意見が割れやすい • 参加の足並みを揃えづらい • オプション・適用範囲の選択肢が多すぎる 46 ファシリテーションが難しい RuboCop設定について話し合う難しさ
Slide 47
Slide 47 text
47 ファシリテーションが難しい RuboCop設定について話し合う難しさ 一人ひとりの文化の違いを尊重しつつ、 設定をひとつに決めなくてはならない
Slide 48
Slide 48 text
48 ファシリテーションが難しい RuboCop設定について話し合う難しさ 一人ひとりの文化の違いを尊重しつつ、 設定をひとつに決めなくてはならない 意見を尊重するため、表明の幅は広く ひとつに決めるため、採決ルールは細かく
Slide 49
Slide 49 text
49 ファシリテーションが難しい 表明の幅は広く・採決ルールは細かく
Slide 50
Slide 50 text
• 意見が割れやすい 50 ファシリテーションが難しい 表明の幅は広く・採決ルールは細かく 意見が割れたときの ルールを細かく設定
Slide 51
Slide 51 text
• 意見が割れやすい 51 ファシリテーションが難しい 表明の幅は広く・採決ルールは細かく 意見が割れたときの ルールを細かく設定 • 参加の足並みを揃えづらい 「気にしない」を表明可に
Slide 52
Slide 52 text
• 意見が割れやすい 52 ファシリテーションが難しい 表明の幅は広く・採決ルールは細かく 意見が割れたときの ルールを細かく設定 • 参加の足並みを揃えづらい • オプション・適用範囲の 選択肢が多すぎる 「気にしない」を表明可に デフォルトに寄せつつ 希望のオプションを表明可に
Slide 53
Slide 53 text
• 時間の確保が難しい • 定期MTGの中に時間を確保する • ファシリテーションが難しい • 意見表明の幅は広く、採決ルールは細かく 53 まとめ:.rubocop.yml をつくる難しさを知り克服する
Slide 54
Slide 54 text
.rubocop.yml の つくりかたを実践する
Slide 55
Slide 55 text
ここから、我々のチームがどういうフローで 話し合いを進めていったかを説明していく 55
Slide 56
Slide 56 text
• デフォルトをベースに.rubocop_todo.yml を減らしていく 56 基本戦略 引用:Koichi ITO, ” Beyond the RuboCop Defaults - Speaker Deck”, https://speakerdeck.com/koic/beyond-the-rubocop-defaults, p.36, 2024/10/24閲覧
Slide 57
Slide 57 text
57 基本的な流れ ①準備をする ②意見を形成する ③意見を表明する ④意見を集約する ⑤コードを修正する ⑥継続する
Slide 58
Slide 58 text
• .rubocop_todo.yml の上から2個Copを選ぶ • 週次MTGで使う議事録(事前に自動作成) にCopの説明を書いておく 58 手順①:準備を行う
Slide 59
Slide 59 text
• MTGがはじまったら、メンバーは説明を読む • その後コードのどの部分に指摘が入るか見ながら確認する 59 手順②:意見を形成する
Slide 60
Slide 60 text
• Slackで投票を行う • 投票は / / / の4択 • :デフォルト設定で有効 • :どちらでもよい • :無効 • :オプション変更して有効 60 手順③:意見を表明する
Slide 61
Slide 61 text
• 基本的には多数決で決める 61 手順④:意見を集約する デフォルト 設定で有効
Slide 62
Slide 62 text
• 基本的には多数決で決める 62 手順④:意見を集約する デフォルト 設定で有効 は投票の総数に入れず 特に話も振らない
Slide 63
Slide 63 text
• まずは各々に理由を尋ね、投票先を変える時間を設ける 63 手順④:意見を集約する 意見が割れたら
Slide 64
Slide 64 text
• 多数派と少数派になったら • 了承をとって多数派の意見を採用 64 手順④:意見を集約する 意見が割れたら デフォルト 設定で有効
Slide 65
Slide 65 text
• 真っ二つに割れたままなら • 自由に書けた方が良いとみなして無効にする 65 手順④:意見を集約する 意見が割れたら 無効 ※あまり良い感じの実例がなかったです
Slide 66
Slide 66 text
• どう設定したいかと理由を尋ねる • その場で選択肢を作り再投票 • それでも割れたら ファシリテーターがジャッジ 66 手順④:意見を集約する に票が入った/設定の希望が出たら
Slide 67
Slide 67 text
• 回り持ちでPR作成の担当者をアサインする • 担当者をラウンドロビンで指名するSlack Appを作って利用 67 手順⑤:コードを修正する
Slide 68
Slide 68 text
• 毎週のチームでの所要時間は15分くらい • これを淡々と続けていく • 週次MTGの時間に余裕がない場合は、無理せずスキップして翌週へ 68 手順⑥:継続する
Slide 69
Slide 69 text
69 そして時は流れ、9ヶ月後……
Slide 70
Slide 70 text
我々は自分たちの.rubocop.yml を 作り上げることができた 70
Slide 71
Slide 71 text
成功の要因を深堀りする
Slide 72
Slide 72 text
72 なぜ、やり切ることができたのか? 要因①:オーナーシップ
Slide 73
Slide 73 text
• 確実に開催されるように準備の担当を自分に固定した • 継続されないのが最大のリスクと捉えたため • メンバー間で温度差はあって当たり前と考え、しくみを作った • 「協力してもらう」スタンスで頑張る人を減らすことが 結局は設定を作り切る近道 73 なぜ、やり切ることができたのか? 要因①:オーナーシップ
Slide 74
Slide 74 text
74 なぜ、やり切ることができたのか? 要因②:チーム文化の下支え
Slide 75
Slide 75 text
• テストを当たり前に書く文化 • 検証コストを最小にするために十分なテストスイートは必須 • 心理的安全性の高い文化 • スタイルの議論はどうしても個々人の好みがぶつかりがち • 反対意見を気軽に表明・議論し、ルールに従って決めてノーサイド、 という「大人の対応」が求められる 75 なぜ、やり切ることができたのか? 要因②:チーム文化の下支え
Slide 76
Slide 76 text
まとめ: .rubocop.yml のつくりかた
Slide 77
Slide 77 text
77 まとめ:.rubocop.yml のつくりかた 定期MTGで少しずつ話し合う 意見表明の幅は広く、採決ルールは細かく オーナーシップを持って話し合いをリードする テストと心理的に安全な文化が下支えする
Slide 78
Slide 78 text
ここまで、.rubocop.yml のつくりかたを説明してきた しかし、一度作り切ることはゴールではない 78
Slide 79
Slide 79 text
.rubocop.yml とはチーム文化の反映 79
Slide 80
Slide 80 text
チームの文化は必ず移り変わる ならば.rubocop.yml も移り変わらなくてはならない 80
Slide 81
Slide 81 text
「定期MTGに組み込む」方法は継続的なメンテへの動線にもなる 81
Slide 82
Slide 82 text
.rubocop.yml を一度作り切ったあとは みなさんの手で文化と共に育てていきましょう 82
Slide 83
Slide 83 text
文化はomakaseできない 自分たちの手で育てて .rubocop.yml に写し取ろう Fin.