$30 off During Our Annual Pro Sale. View Details »

Kaigi on Rails 2022 - 既存Railsアプリ攻略法 CTOが見ること・やること・考えること

Kaigi on Rails 2022 - 既存Railsアプリ攻略法 CTOが見ること・やること・考えること

Fujimura Daisuke

October 21, 2022
Tweet

More Decks by Fujimura Daisuke

Other Decks in Technology

Transcript

  1. 2022-10-21 Kaigi on Rails 2022 STORES 株式会社 CTO 藤村大介 既存Railsアプリ攻略法

    CTOが見ること・やること・考えること
  2. 自己紹介 - お仕事 2 時期 2008~2012 2013~ 2015~ 2020~ 会社

    いろいろ Quipper マチマチ STORES バックエンド Rails Rails Rails Rails, etc. フロントエンド jQuery, Backbone.js etc. Backbone.js etc. React.js React.js, Vue.js 立場 ほぼメンバー いわゆるEM CTO CTO 藤村大介 twitter.com/ffu_ github.com/fujimura note.com/fujimuradaisuke
  3. 自己紹介 - 書いたり発表したもの 3 Rails Developer Meetup 2019 入門 名前

    WEB+DB PRESSの特集のダイジェスト版 https://speakerdeck.com/fujimura/ru-men-ming-qian WEB+DB PRESS Vol.110 特集 名前付け大全 「よい命名とは」をガチで考えてみたやつ https://gihyo.jp/magazine/wdpress/archive/2019/vol110
  4. 自己紹介 - ポッドキャスト 4 論より動くもの.fm 藤村がホストになって、技術や技術にまつわることについてざっくばらんに話す Podcastです。 文字起こしもあるよ! 論より動くもの.fm |

    Podcast on Spotify 論より動くもの.fm on Apple Podcasts 論より動くもの.fm カテゴリーの記事一覧 - STORES Product Blog
  5. 自己紹介 - 代表作 5 Haskellのプロジェクト生成ツール $ bundle gem みたいなやつ。当 時いいツールがなかったので作った

    git-grepの結果で置換とリネーム $ git grep | xargs sed -i s/foo/bar/ が面倒なので作った rspec-railsのHaskell版 正確にはRackにあたる層のためのも の。無かったので作った
  6. 6

  7. STORES のミッション こだわりや情熱、たのしみに駆動される経済をつくる 熱中しているひとたちから生み出される、 多様な商品やサービスが街に溢れる世界。 その経済を支える、デジタルインフラを提供する。 7

  8. サービス紹介 8 お店のデジタルを まるっとサポート。 個人や中小事業の方々に向けて、 お店のデジタル化をまるっと 実現できる価値を提供しています。

  9. 今日の話 9 • 既存のRailsアプリケーションを触る機会は多い • 目指すのは「プロダクト開発のアジリティを上げ、スムーズにお客さんに 価値を提供し続ける」こと • ベテランRailsエンジニアおよびCTOとして、どういう観点で何を見て、何 を目指してどんなことをするのか?

    • 裏テーマ:PMIで何をするか、CTOという経営幹部がRailsアプリケーショ ンを触るときに何を考えているか
  10. 最近のお仕事 10 • PMI ◦ = Post Merger Integration ◦

    M&Aのあとに経営とかプロダクトとか組織とかをいい感じにして1つ のチームになるやつ
  11. 2021年夏 SHOP FORCE社がSTORESにジョイン 11 • 夏にSHOP FORCE社がSTORES(当時はhey)にジョイン • 中目黒のSHOP FORCEオフィスに出社しはじめる

    ◦ くわしくはこちら: 入社してすぐ任されたショップフォースのPMI。 STORES ブランドアプリ をリリースするまで|STORES People
  12. 2021年夏 SHOP FORCE社がSTORESにジョイン 12

  13. 中目黒に行くようになってすぐの状況理解とアクションプラン 13 • パッと見た感じ、課題は色々ある • ひとまず、優先順位はあまり気にせず、手当たり次第に直す! • Low Hanging Fruitsがめっちゃある。これらを収穫しまくったあとで中長

    期的な大きな優先順位は考えよう、と思った ◦ 良く言えばOODA Loop、悪く言えばただのゲリラ戦
  14. 中目黒に行くようになってすぐの状況理解とアクションプラン 14 • 「優先順位はあまり気にせず、手当たり次第に直す!」 • とはいえ、手当り次第にも観察と方向決定があったはず • 何を見て、何のために、何をしたの?

  15. 既存Railsアプリ攻略法 CTOが見ること・やること・考えること あるいはスタートアップPMI戦記 Rails編 ということではじまり! 2022-10-21 Kaigi on Rails 2022

    STORES 株式会社 CTO 藤村大介
  16. まずは概要をつかむ 16 とりあえず規模感とざっくりした雰囲気、全体像を把握しようとしました。

  17. 概要理解: $ rake routes 17 • 目的 ◦ どんなエンドポイントがあるのか、URLの雰囲気をざっくり掴む •

    見ること ◦ $ rake routes をじっと眺める ◦ テキストファイルに落とすと便利 • わかること ◦ 量と種別 ▪ どのくらいの量のエンドポイントがあるのか? ▪ HTMLを返すいわゆるRailsのView、API、よくわからないやつがそれぞれどのくらい あるか ◦ 質 ▪ APIのバージョニングは? ▪ URL設計の品質はどうか? ▪ リソース設計で色々見えてくる
  18. 概要理解: $ rake stats 18 • 目的 ◦ 何がどのくらいあるかざっくり掴む •

    見ること ◦ $ rake statsをじっと眺める • わかること ◦ モデルはいくつあるか ▪ 規模感を測るうえで一番わかりやすい指標。500を超えると気合いが入ってくる ◦ テストはどのくらい書かれているか ▪ Code to Test Ratioと、System/Request/Unitそれぞれ分量の割合をみる ◦ JavaScriptはどのくらいあるか ▪ フロントエンドの作り込み具合がわかる ◦ Rails標準以外のディレクトリはなにがどのくらいあるか? ▪ 設計思想がわかる ◦ 非同期処理の割合は? ▪ どのくらい非同期処理にするかは結構リポジトリによって違う
  19. 概要理解: Gemfile, package.json 19 • 目的 ◦ どんなライブラリが使われているのか把握する ◦ 選球眼とノリを理解する

    • 見ること・考えること ◦ deviseは使われているか? ▪ 認証周りの読み方に大きな差が出る ◦ 設計に踏み込むタイプのGemは使われているか? ▪ Railsのレールに乗って素朴に作るか、大きめのライブラリを使って組むかのノリがわ かる ▪ pundit、cancancanあたり ◦ 主要なライブラリのバージョンは? ▪ アップデート大変そうなやつをみたり ◦ ファイル保存系ライブラリは何を使っている? ▪ Paperclipだとオッとなる ◦ 知らないGemはあるか?あるなら、それは何なのか? ◦ メンテナンスされていないことがわかっているGemはあるか?
  20. 概要理解: モデルの行数 20 • 目的 ◦ 重要なモデル、デカいモデルを把握する • 見ること ◦

    $ git ls-files app/models | xargs wc -l | sort ◦ 多くのことをやっているモデルはなにか ◦ メチャクチャに大きいモデルはあるか ◦ user.rb に匹敵するやつはどれ?
  21. 概要理解: モデルのテストの行数 21 • 目的 ◦ 重要なモデル、デカいモデルを把握する ◦ 見ること •

    $ git ls-files spec/models | xargs wc -l | sort ◦ 重要もしくは複雑なモデルはどれか? ◦ テストケースが多いモデルは重要度もしくは複雑性が高いと考えられる
  22. 概要理解: app/models/user.rb 22 • 目的 ◦ そのリポジトリでのコードのスタイルを把握する ◦ 仕様や実装の観察と理解 •

    見ること ◦ app/models/user.rb を流し読みする • 考えること ◦ 様々な観点があるが、いったん事前の観点を捨てて流し読みすると、様々なことがわかる ◦ user.rb はお手入れが行き届いている場合が多いので、そのリポジトリでのRubyコード の書き方の癖みたいなものもわかる
  23. 概要理解: config/initializers/* 23 • 目的 ◦ 実装の観察と理解 • 見ること ◦

    ここには色々なものが眠っているので、これも同じく事前の観点を捨てて一通り流し読み して状況把握する ▪ ミドルウェア、外部のAPI、などなど ◦ 各種クレデンシャルの扱い方の癖を通して、なんとなくDevOps的な練度がわかる
  24. 概要理解: コードの質感 24 • 目的 ◦ スタイルの理解 ◦ 可読性、修正容易性、セキュリティのために直すべきところの発見 •

    見ること ◦ コードフォーマット ◦ idiomaticなRubyコードか ◦ eval, send, method_missing など大胆な技術の使われぶり
  25. 概要理解: 開発環境 25 • 目的 ◦ オンボーディングコスト削減のためにするべきことの発見 • 見ること ◦

    どのくらいdocker-composeに乗っているか ◦ seeds.rb で開発に使えるデータが作られるか ◦ ドキュメントの通りに作れるか • 考えること ◦ ここは考えずに片っ端から直す
  26. 概要理解: テスト・CI 26 • 目的 ◦ 品質保証やデリバリーの練度の把握と、改善方針を考えるための材料集め • 見ること ◦

    そもそもあるか(テストもCIも) ◦ 実行時間はほどほどになっているか ◦ どのくらい安定しているか ▪ Flakyなテストはどこにあるか ◦ CIの通過をもってどのくらいアプリケーションが正しく動作するか確認できるか ▪ これはもともといたメンバーに感触を聞くのが早くて正確
  27. 概要理解: リリース手順・サイクル 27 • 目的 ◦ 可能な限り自動化し高頻度でリリースするために何をするべきか把握する • 見ること ◦

    リリース手順は自動化されているか ◦ リリースサイクルは明文化されているか ◦ されている場合、手順が明確か ◦ 頻度はどうか
  28. 概要理解: 監視 28 • 目的 ◦ 運用で改善する点はあるか確認 ◦ パフォーマンスはいかほどか •

    見ること ◦ APM ▪ Datadog、New Relicなど ◦ AWSの各種ログ
  29. 概要理解 まとめ 29 • $ rake routes • $ rake

    stats • Gemfile • package.json • モデルの行数 • モデルのテストの行数 • app/models/user.rb • config/initializers/* • コードの質感 • 開発環境 • テスト・CI • リリース手順・サイクル • 監視 といったあたりの把握で、だいたいどんなRailsアプリケーションがどのように動いているのかわかり ました。 では直しますか…とその前に!
  30. 既存Railsアプリに触れるときの心構え 30 あるいは、新たに事業/プロダクト/コードを受け入れるときの心構え

  31. 心構え: 事業をやっていると、常にあらゆる状況でベストなコードは書けない 31 • その時はベストなコードでも、状況が変わるとベストではなくなることがある ◦ そして、状況は変わっていく • そもそも時間の都合でベストのコードが書けない場合もある ◦

    スタートアップという、来月生きるか死ぬかの世界では特にそう • なので、ベストではないコードはどうしても生まれる ◦ 何も悪くないし避けられない
  32. 心構え: 「良くない」と思うコードに腹を立てても意味はない 32 • 実業界で出会うコードは、それぞれにそれぞれの事情があって、現状がある • 生き延びた事業のプロダクションコードは形はどうであれ尊い • なんにせよ、やれることは直すか、直さないかしかない ◦

    我々プログラマーは直すことができる。直そう
  33. 心構え: 毎日少しづつ改善すれば必ずよくなる 33 • 事業存続に影響があるくらい内部品質が悪ければ、作り直す判断もあるだろう • しかし、だいたいのプロダクションコードは漸進的に改善できる、と僕は思っている ◦ 今回もそうだった •

    「直る」という事実で、改善を積み上げて課題を解決する文化を作りたかった
  34. 心構え: いったん「しゃがむ」判断も大事 34 • 「プロダクト開発のアジリティを上げ、スムーズにお客さんに価値を提供し続ける」ために内部 品質の改善は重要 • しゃがむ=内部品質の改善に時間を使う必要があれば、その判断をし、関係者の理解をとりつ け、実行する ◦

    この意思決定と実行を行うのは、ソフトウェアエンジニアの仕事 ◦ これをやるには、関係者との強固な相互理解・信頼関係が必要 @t_wada さんの 質とスピード(2022春版、質疑応答用資料付き) 53p より
  35. 既存Railsアプリに触れるときの心構え まとめ 35 あるいは、新たに事業/プロダクト/コードを受け入れるときの心構え まとめ • 新しい事業/プロダクト/コードに触れるときは、 ◦ とにかく毎日少しづつ改善する ◦

    その上で「しゃがむ」必要があれば決断し、しゃがむ ▪ 「プロダクト開発のアジリティを上げ、スムーズにお客さんに価値を提供し続ける」 ために内部品質を改善する ◦ そのために関係者との強固な相互理解と信頼関係を作る
  36. やったこと 36 ということで、概要の把握と心構えができたので、実際に何をしたかを紹介します。

  37. やった: 開発環境の整備 37 • 目的 ◦ 新メンバーのオンボーディングコストを減らす • やったこと ◦

    rails db:seeds が通るようにする ◦ docker-compose化が部分的だったので、完遂 ◦ 不要な環境変数を削除するなど ◦ 環境構築のドキュメントをesaからリポジトリのREADMEに移す ◦ レビューによる知識の共有や更新性のため、リポジトリに置いておいたほうが良い
  38. やった: デプロイプロセスの自動化 38 • 目的 ◦ プロダクト改善速度の向上、障害対応コストの削減 • やったこと ◦

    もともとmasterにマージされると本番にデプロイされるようになっていたが、頻度は随 時、リリース用のPRは手動作成だった ▪ 結果、リリースの単位は比較的大きくなっていた ◦ リリース用のPRの作成をGitHub Actionsで自動化し、週二回の定期リリースとした ▪ 頻繁なリリースによりチームの「リズム感」も良くなった
  39. やった: 内部品質改善に時間を使うという意思決定 39 • 目的 ◦ スムーズにお客さんに価値を提供し続けるため、プロダクト開発のアジリティを上げる ▪ 内部品質に改善の余地があり、ここの改善が数ヶ月後のプロダクト改善速度に大きく インパクトがあると判断した

    ▪ 定量にするまでもなく、感覚的に明らかだった • やったこと ◦ 他業種のチームメイトとの相互理解、信頼関係を作る ▪ 事業担当、PdM、サポート、経営メンバーなど ▪ ランチ、1on1、飲み会、ふとした雑談などで、人として打ち解ける ▪ おれたちRubyistは“Nice” であるということを知っているはず…! ◦ 内部品質改善の価値を理解してもらう ▪ @t_wada さんの「質とスピード」を読んでもらったり、自分で読み直して説明した りするとよい ◦ 時間を使うと決め、合意をとりつけ、改善に取り組む ▪ なぜ?がソリッドなら、ビジネス側のひとも理解してくれます
  40. やった: feature specからsystem specへの移行 40 • 目的 ◦ 新しく標準的な手法に変更してメンテナンスコストを削減 •

    やったこと ◦ まずはfeature/system spec以外への副作用をなくす ▪ RSpec.configure do 内を整理してFeature spec用のものを spec/feature_helper.rb に切り出し ◦ Feature Spec用とそれ以外でも使うやつが混在していたヘルパーメソッドを分類 ◦ system specへ移行 ▪ spec/system_helper.rb を新設 ◦ 少しづつ書き換えて問題なさそうだったのであとは一括置換などでガッと
  41. やった: 使われていないコード、Gemの削除 41 • 目的 ◦ 実装時の認知負荷軽減による生産性改善 ◦ あらゆる作業に細かく大量に積み上がっている見えないコストだと思っている ◦

    部屋が散らかっていると集中できないのと同じ • やったこと ◦ 明らかなものから、毎日着実に消していく ◦ 細かく着実に消していけば必ずキレイになります ▪ 部屋の掃除と同じ ◦ 副業のチームメンバーにお願いしたりもした ▪ 頼みやすいし、手をつけやすいタスク
  42. やった: RSpecのfilter runを有効にする 42 • 目的 ◦ 僕が欲しかったので。。。 • やったこと

    ◦ + config.filter_run_when_matching :focus
  43. やった: s/FactoryBot.create/create/ 43 • 目的 ◦ 認知コスト削減 ◦ Spec内に大量に出てくる FactoryBotという文字を脳が認識しているが、そのコストがもっ

    たいない • やったこと ◦ 一括置換 ◦ $ git gsub 'FactoryBot.(create|build)' '$1' spec ▪ https://github.com/fujimura/git-gsub 便利ですよ(宣伝)
  44. やった: transactional testを有効にする 44 • 目的 ◦ 遅い!!! • やったこと

    ◦ Database CleanerのStrategyが truncation でテストの実行が遅かったのでtransaction にして速くした ▪ strategy = :transaction で実行して通ったら実行時にExampleのMetadataを 書き換えるようにした ▪ くわしくはこちら RSpecのテストコードを実行時に書き換えて実行速度を改善した話 - STORES Product Blog
  45. やった: Request specで叩くエンドポイントはリテラルを使う 45 • 目的 ◦ Request Specがエンドポイントの検証になっている状態にしたい ◦

    テストで post_path などnamed routesが使われていた ◦ エンドポイントの検証という意味では、文字列リテラルのほうがよいと判断 ▪ get post_path ではなく get “/post/#{post.id}” としたい • やったこと ◦ テスト実行時にnamed routesを文字列リテラルに書き換える仕組みを作り改善した ▪ transactional testを直したときの仕組みを流用
  46. やった: annotate自動化 46 • 目的 ◦ 人間の仕事を減らしたい • やったこと ◦

    たまに人間がやる、ずれることもある、という感じだった ◦ GitHub Actionsでmasterにコミットがあったらannotateを実行して、差分があれば自動 でBotがPRを出すようにした https://github.com/ctran/annotate_models
  47. やった: 開発環境SSL化 47 • 目的 ◦ サードパーティーのインテグレーションがある機能をローカルで使えるようにする ◦ ID連携など。できていないとSSLが必要な処理がローカルでテストされることはないし、必 要になってから整備するのは遅い。なので先にやっておく

    • やったこと ◦ オレオレ証明書を発行してMac OSのKeychainにインストールするスクリプトを書き、 docker-composeでnginxのリバースプロキシを立てて…というよくあるやつ ◦ OpenSSLで作ったけどmkcertでもよかった
  48. やった: rubocop --auto-correct 自動実行 48 • 目的 ◦ コードフォーマットやスタイルを揃えて、読むときの認知コストを下げたい ◦

    認知コストはまじで我々の可処分時間と注意力を奪っていると思うので、下げるの大事だ と思っている • やったこと ◦ See たまってしまった .rubocop_todo.yml をGitHub Actionsで継続的かつ自動的に倒す方 法 - STORES Product Blog ▪ 要は rubocop –auto-correct をGitHub Actionsで実行、 .rubocop_todo.yml を再生成、 PRを出す、するやつ ◦ prettier-rubyにすればよかったかも、という後悔はある
  49. やった: rubocop --auto-correct 自動実行 49 .rubocop_todo.yml の行数の推移(グラフを出すコードはこちら)

  50. やった: Trailing Whitespaces一斉削除 50 • 目的 ◦ 認知コスト削減 • やったこと

    ◦ $ git ls-files app spec lib config | grep -E '.rb$' | xargs gsed -r -i 's/\s+$//
  51. いろいろやった!! 51 だいぶ、よくなりました

  52. 再掲:既存Railsアプリに触れるときの心構え 52 あるいは、新たに事業/プロダクト/コードを受け入れるときの心構え まとめ • 新しい事業/プロダクト/コードに触れるときは、 ◦ とにかく毎日少しづつ改善する ◦ その上で「しゃがむ」必要があれば決断し、しゃがむ

    ▪ 「プロダクト開発のアジリティを上げ、スムーズにお客さんに価値を提供し続ける」 ために内部品質を改善する ◦ そのために関係者との強固な相互理解と信頼関係を作る
  53. やったこと まとめ 53 • 開発環境の整備 • デプロイプロセスの自動化 • 内部品質改善に時間を使うという意思決定 •

    system spec移行 • 使われていないコード、Gemの削除 • RSpecのfilter runを有効にする • s/FactoryBot.create/create/ • transactional testを有効にする • Request specで叩くエンドポイントは実際の値を使うようにしていく • annotate自動化 • 開発環境SSL化 • rubocop --auto-correctを定期実行してPRを出す • Trailing whitespaces一斉削除
  54. 再掲:既存Railsアプリに触れるときの心構え 54 あるいは、新たに事業/プロダクト/コードを受け入れるときの心構え まとめ • 新しい事業/プロダクト/コードに触れるときは、 ◦ とにかく毎日少しづつ改善する ◦ その上で「しゃがむ」必要があれば決断し、しゃがむ

    ▪ 「プロダクト開発のアジリティを上げ、スムーズにお客さんに価値を提供し続ける」 ために内部品質を改善する ◦ そのために関係者との強固な相互理解と信頼関係を作る
  55. やったこと まとめ 55 • 開発環境の整備 • デプロイプロセスの自動化 • 内部品質改善に時間を使うという意思決定 •

    system spec移行 • 使われていないコード、Gemの削除 • RSpecのfilter runを有効にする • s/FactoryBot.create/create/ • transactional testを有効にする • Request specで叩くエンドポイントは実際の値を使うようにしていく • annotate自動化 • 開発環境SSL化 • rubocop --auto-correct を定期実行してPRを出す • Trailing whitespaces一斉削除
  56. 既存Railsアプリ攻略法 CTOが見ること・やること・考えること まとめ 56 • 見ること・やること ◦ 資料を見てくれ • 考えること

    あるいは心構え ◦ 新しい事業/プロダクト/コードに触れるときは、 ▪ とにかく毎日少しづつ改善する ▪ その上で「しゃがむ」必要があれば決断し、しゃがむ ▪ 「プロダクト開発のアジリティを上げ、スムーズにお客さんに価値を提供し続 ける」ために内部品質を改善する ▪ そのために関係者との強固な相互理解と信頼関係を作る
  57. ご清聴ありがとうございました 57 今日の話の内容が何かしら皆さんのお役に立てると幸いです。 この話、もしくこの話と関係ない話などなど よかったらぜひお話しましょう〜 Meetyでお気軽にご連絡ください!