Share
Embed
技術的負債の借り換え on Ruby and Rails update
https://kaigionrails.org/2023/talks/ginkouno/
Kaigi on Rails 2023登壇時の資料です。
ginkouno
November 05, 2023
Transcript
77 slides
-
永久保存版Railsアップデートガイド 永久保存版!?伊藤さん式・Railsアプリのアップグレード手順 ”Rails 以 外 のgemを 全 部 最 新
にする Railsのアップデートに引きずられて他のgemも上げることが多いので、先にRails以外のgemを最新にして おくとRailsアップデート後に不具合が起きた時に切り分けがしやすいです。 ” ”コラム:gemは普段からこまめにバージョンアップしよう gemのバージョンアップ作業は実際にやってみると、かなり骨が折れると思います。 古いバージョンのgemが多ければ多いほど、この作業のしんどさが増えるので、日頃からこまめにgemを最 新版にアップデートしていくことをお勧めします。” -
Rails、RubyのEOL 着手 gem update その1 gem update その2 gem update
その3 gem update その4 想定される事態 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% 世間の金利の例 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% 世間の金利の例 EOL超過はこの辺 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% 世間の金利の例 EOL超過はこの辺 こっちに借り換え -
Rails、RubyのEOL 着手 gem update その1 gem update その2 gem update
その3 gem update その4 -
Rails、RubyのEOL 着手 gem update その1 gem update その2 gem update
その3 gem update その4 -
Rails、RubyのEOL 着手 gem update その1 gem update その2 gem update
その3 gem update その4 完済まで至らずとも、借り換え手数料 = 工数 をあまりかけずに 利率の低い負債に借り換えたい -
def self.up set_table_comment :table_name, "A table comment" set_column_comment :table_name, :column_name,
"A column comment" end def self.create_table :table_name, :comment => "A table comment" do |t| t.string :column_name, :comment => "A column comment" end • Rails5.0から同様の機能が搭載されはじめ、5.1で十分な機能に • migration_comments gemの最後のcommitは7年前 • Rails6.1では動かない migrationでコメントをつけることができる -
対策案 ・Rails6.1で使えるようにforkしてcommitを積む ← もうほかの利用者も居なそう、メンテコスト増 ・migration fileをRails標準機能利用に書き換える ← migration fileが1540、書き換え箇所が580で少々怖い ・この際RidgePoleに移行して圧縮する
← 個人的には好みだけど依存するgemの増加を懸念する意見 ・wrapperとなるmethodを作り、migration_commentsを利用停止 ← code少量、標準機能使うしメンテコスト小【採用】 -
wrapperとなるmethodを作る(1) migration_commentsのmethodを呼ぶと、 標準のRailsの機能が呼ばれるようにする(set、remove) module ActiveRecord class Migration def set_column_comment(table_name, column_name,
comment) change_column_comment(table_name, column_name, comment) end def remove_column_comment(table_name, column_name) change_column_comment(table_name, column_name, nil) end # 以下略 -
wrapperとなるmethodを作る(2) migration_commentsのmethodを呼ぶと、 標準のRailsの機能が呼ばれるようにする(t.comment) module ConnectionAdapters module MySQL class Table def
comment(comment) ActiveRecord::Migration.change_table_comment(name, comment) end end end end -
動作確認 改修前とtable構造に変化がないか、 table schema同士のdumpを比較して確認する % mysql -u root --no-data co_development
> schema_without_migration_comments % diff schema_with_migration_comments schema_without_migration_comments c12177c12177 < -- Dump completed on 2023-02-14 16:08:03 --- > -- Dump completed on 2023-02-14 17:05:28 -
CI監視 migration_commentsのmethodが新しく呼ばれないよう、 CIで監視する #!/bin/bash if find/db/migrate | sort | awk
-F/ ‘int($3) > 2023213000000’ | xargs grep -Hn ‘set_column_comment\|set_table_comment\|remove_column_comment\|remove_table_comm ent\|t\.column’; then echo “migration_comments gemのmethodを使わず、Railsが提供するmethodを利用して 下さい” exit 1 fi -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 Rails6.1にUpdate可能 Rails標準機能利用 + 少量のcode -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 Rails6.1にUpdate可能 Rails標準機能利用 + 少量のcode みなさん的には何番でしょう? -
複数DBに対応できるgem Book.with_readonly { Book.first } # replica dbから読む Book.with_readonly do
author = Book.first.authors.first # replica dbから読む author.family_name = 'new_family_name' Author.with_writable do author.save! # primary dbに書く end end -
Ruby on Rails Guidesの指示通りにdatabase.ymlを書き換える database.ymlの修正 production: primary: database: my_database username:
root password: <%= ENV['ROOT_PASSWORD'] %> adapter: mysql2 primary_replica: database: my_database username: root_readonly password: <%= ENV['ROOT_READONLY_PASSWORD'] %> adapter: mysql2 replica: true -
wrapperとなるmethodを作る switch_pointと同名のwrapper methodを作り、Rails標準のmethodを呼ぶ class ApplicationRecord < ActiveRecord::Base self.abstract_class = true
connects_to database: { writing: :primary, reading: :primary_replica } def self.with_readonly(&block) ActiveRecord::Base.connected_to(role: :reading, &block) end end -
動作確認 docker containerを複数立ち上げてそれぞれのquery logを監視 read / writeが各dbに対しSQLが意図通り振り分けられ発行されるか確認 services: primary_mysql: build:
./mysql/primary container_name: ‘primary_mysql’ ports: -“3306:3306” replica_mysql: build: ./mysql/replica container_name: ‘replica_mysql’ ports: - “3307:3306” -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 Rails6.1にUpdate可能 Rails標準機能利用 + 少量のcode -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Rails6.1に Updateできない状態 みなさん的には何番でしょう? Rails6.1にUpdate可能 Rails標準機能利用 + 少量のcode -
sidekiqのふつうの使い方 class MessageJob include Sidekiq::Job def perform(article_id, message) Message.create!(article_id: article_id,
message: message) end end MessageJob.new.perform_async(article_id, “hello”) Jobを作る 呼び出す -
代替methodを定義 ・代替methodを定義、WrapperClassのinstanceを返す ・Moduleでincludeし、どのClassからも呼べるようにしておく module SidekiqDelayPatch module Klass def sidekiq_worker_delay(**sidekiq_option) return
SidekiqDelayPatch::DelayWrapper.new(self, (**sidekiq_option)) end end end Module.__send__(:include, SidekiqDelayPatch::Klass) -
任意のmethodを受け取る仕組みを作る ・WrapperClassのinstanceは、初期化時にClass名を取得 ・method_missingでmethod名、引数を取得、YAML Dumpして共通Jobに渡す class DelayWrapper < DelayWrapperBase def initialize(klass,
**sidekiq_option) @class_name = klass.to_s @sidekiq_option = sidekiq_option end def method_missing(method_name, *args, **kwargs, &block) CommonJob .set(@sidekiq_option) .perform_async(args_yaml(method_name, args,kwargs)) end end -
共通Jobが任意のmethodを実行 ・渡されたClass名、method名、引数を復元し実行 class CommonJob include Sidekiq::Job def perform(args_yaml) klass, method_name,
args = ::YAML.load(args_yaml) kwargs = args.list.is_a?(Hash) ? args.pop : {} if klass.ancestors.include?(ActionMailer::Base) klass.public_send(method_name, *args, **kwargs).deliver_now else klass.public.send(method_name, *args, **kwargs) end end end -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Ruby3.0に Updateできない状態 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Ruby3.0に Updateできない状態 Ruby3.0にUpdate可能な状態 自前codeだが将来的に使えなくなる可能性 -
6 5 4 3 2 1 ウ◯ジマ くん ミ◯ミの 銀次
ほのぼの 約束 銀行 カーローン 住宅 ローン 完済 10日で5割 10日で1割 年4.0%〜 18.0% 年0.85%〜 3.5% 0.319%〜 1.58% 0% Ruby3.0に Updateできない状態 Ruby3.0にUpdate可能な状態 自前codeだが将来的に使えなくなる可能性 みなさん的には何番でしょう? -
Keep Problem Try とりあえずUpdateができた ドメイン知識深い開発者や チーム横断での協力得られた テストが書かれていた Updateが遅れて工数増大 負債を残したところも 定常的なリソースの確保
→ 実現 「アプリケーション基盤G」 技術負債解消や基盤開発を行う部門