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
【 安全に倒し切るリリース 】 をするために 15年来レガシーシステムのフルリプレイス挑戦記 2025-03-22 PHPerKaigi 2025 1
Slide 2
Slide 2 text
こんにちは! 2
Slide 3
Slide 3 text
安全なリリース 3
Slide 4
Slide 4 text
安全なリリース したいですよね? 4
Slide 5
Slide 5 text
私たちは先日 5
Slide 6
Slide 6 text
15年物のレガシー機能を 6
Slide 7
Slide 7 text
15年物のレガシー機能を 同時並行で2つ 7
Slide 8
Slide 8 text
15年物のレガシー機能を 同時並行で2つ ある検証手法を用いて 8
Slide 9
Slide 9 text
15年物のレガシー機能を 同時並行で2つ ある検証手法を用いて ほぼ総書き換え 9
Slide 10
Slide 10 text
障害の香り 10
Slide 11
Slide 11 text
しかし 11
Slide 12
Slide 12 text
リリース後の障害ゼロ! 12
Slide 13
Slide 13 text
300秒のクエリが0.8秒に! 13
Slide 14
Slide 14 text
デザインパターンの導入! 14
Slide 15
Slide 15 text
障害の香り 15
Slide 16
Slide 16 text
⾃⼰紹介 ● さくらい( : @saku_rye) ● 新卒4年⽬、エンジニア歴 2年半 CS から未経験 社内ジョブチェン ● Webアプリ開発のPHPer ● 初めてのPHPコミュニティ登壇 & tech登壇 16
Slide 17
Slide 17 text
15年物のレガシー機能を 同時並行で2つ ある検証手法を用いて ほぼ バグ0で総書き換え 17
Slide 18
Slide 18 text
15年物のレガシー機能を 同時並行で2つ ある検証手法を用いて ほぼ バグ0で総書き換え 18 リプレイス この一連のリリースをここでは リプレイス
Slide 19
Slide 19 text
なぜ / どうやって 安全に倒し切るリリース を実現したのか について話します 19
Slide 20
Slide 20 text
本⽇のターゲット ● 安全最優先のリリースが必要な⽅ ● リプレイス‧⼤規模リファクタに直⾯している⽅ ● レガシーシステムと⽇々向き合う⽅ 20
Slide 21
Slide 21 text
GOAL & NOT GOAL ● 俺たちが考える最強検証メソッド💪 の紹介ではない ● ただ実際に⽴ち向かった実績のある⽅法 ● 他のプロダクトでも応⽤可能な知⾒を共有 21
Slide 22
Slide 22 text
● この発表をtipsやインスピレーションとして 使えるところは使って、⾊々な形に合った 「安全に倒し切ったリリース」があると良い ● 安全なリリースのための選択肢の⼀つと なりますように🙏 GOAL & NOT GOAL 22
Slide 23
Slide 23 text
おしながき 23
Slide 24
Slide 24 text
おしながき 安全に倒し切った 背景と課題 安全に倒し切るための「ペンギンテスト」 ペンギンテスト後 その他の安全対策 1 2 3 24
Slide 25
Slide 25 text
おしながき 安全に倒し切った 背景と課題 安全に倒し切るための「ペンギンテスト」 ペンギンテスト後 その他の安全対策 1 2 3 25
Slide 26
Slide 26 text
ある日 26
Slide 27
Slide 27 text
27 弊社のえらいおじさん
Slide 28
Slide 28 text
ユーザーが待ち望む ⼤きな新機能 ⼤きな価値提供 28
Slide 29
Slide 29 text
29 我々「やるぞ💪」
Slide 30
Slide 30 text
30 15年前からある スパゲッティコード
Slide 31
Slide 31 text
31 GO!!
Slide 32
Slide 32 text
● 15年以上前から存在する、 プロダクトの中でも最もレガシーな箇所 ● 以前からパフォーマンスの問題や 要望機能が追加できないなどの問題があった 対象箇所について 32
Slide 33
Slide 33 text
● 同時に最もコアで価値のあるコード リスクと影響範囲が⼤きい ● ⼤掛かりなリファクタはできておらず 15年間微細なパッチのみで凌いできた 対象箇所について 33
Slide 34
Slide 34 text
リプレイスには 課題がたくさん 34
Slide 35
Slide 35 text
リプレイスの主な課題 1. システムの根幹機能 2. 失敗した時のリカバリが困難 3. 影響範囲が広すぎる 1 2 3 35
Slide 36
Slide 36 text
● 1時間で10万リクエスト ● プロダクトの中核処理 ● 他機能との結びつきが強い基礎機能 ● 障害になったらコールセンターがパンク 補償問題に発展する システムの根幹機能である 課題 1 36
Slide 37
Slide 37 text
● 破壊的な副作⽤があるリリース ソースの差し戻しだけで解決できない ● データが常に動的に変わる バックアップでの障害対応が困難 失敗した時のリカバリが困難 課題 2 37
Slide 38
Slide 38 text
● 1つの決定に対する変数が多い 網羅性のあるテストを作るのは⾮現実的 ● 考慮漏れの可能性を潰しきれない ● ⾒落としのない検証が困難 影響範囲が広すぎる 課題 3 38
Slide 39
Slide 39 text
リスク モリッモリッ 39
Slide 40
Slide 40 text
しかし 40
Slide 41
Slide 41 text
障害もバグも ダメ 絶対 41
Slide 42
Slide 42 text
EC事業者の管理システム 「何が 何個 売れたか」 をベースに大小様々 約200機能 42 私たちのプロダクトについて
Slide 43
Slide 43 text
EC事業者の管理システム 「何が 何個 売れたか」 をベースに大小様々 約200機能 43 私たちのプロダクトについて ここを触る→
Slide 44
Slide 44 text
44
Slide 45
Slide 45 text
45
Slide 46
Slide 46 text
今回は安全が最優先 最大限 安全に倒し切る ことが絶対条件 事業部 サイド 46
Slide 47
Slide 47 text
それでも 47
Slide 48
Slide 48 text
プロダクトが持つ大きな責任 顧客への価値提供 48
Slide 49
Slide 49 text
GO!! 49
Slide 50
Slide 50 text
50 リプレイスを決意
Slide 51
Slide 51 text
ちなみに 51
Slide 52
Slide 52 text
テストコードを書くってのはどう? ● 変数が多いロジックのウン万⾏のテスト ● 将来の属⼈的な負債になる ● データが動的に変化するため⾮現実的 1億レコード超のデータから処理することも 52 今回はテストコード以外の方法で 安全に倒すという判断
Slide 53
Slide 53 text
我々はどう立ち向かったか 53
Slide 54
Slide 54 text
普段のリリース 1. 実装完了 2. 3. 検証 4. 5. 6. リリース 1 2 3 54
Slide 55
Slide 55 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 55
Slide 56
Slide 56 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト ←??? 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 56
Slide 57
Slide 57 text
今回のメイン 🐧 ペンギンテスト🐧 57
Slide 58
Slide 58 text
おしながき 安全に倒し切った 背景と課題 安全に倒し切るための「ペンギンテスト」 ペンギンテスト後 その他の安全対策 1 2 3 ✔ 58
Slide 59
Slide 59 text
2. 安全のための「ペンギンテスト」 🐧 ペンギンテストの 概要 🐧 ペンギンテストの 仕組み 🐧 ペンギンテストで直⾯した 問題 59
Slide 60
Slide 60 text
2. 安全のための「ペンギンテスト」 🐧 ペンギンテストの 概要 🐧 ペンギンテストの 仕組み 🐧 ペンギンテストで直⾯した 問題 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
リプレイス最大の問題 それは 67
Slide 68
Slide 68 text
いかにして 見落としのないテスト をするか 68
Slide 69
Slide 69 text
● 1つに決定に対する変数が多い 網羅性のあるテストを作るのは⾮現実的 ● 考慮漏れの可能性を潰しきれない ● ⾒落としのない検証が困難 影響範囲が広すぎる 課題 3 69
Slide 70
Slide 70 text
ただ言い換えれば 70
Slide 71
Slide 71 text
見落としのない検証ができる = 安全に倒せる 71
Slide 72
Slide 72 text
72
Slide 73
Slide 73 text
オムロン社によるテスト 方法(2012)by publickey https://www.publickey1.jp/blog/12/_1040.html 73
Slide 74
Slide 74 text
これだ! 我々 オムロン社によるテスト 方法(2012)by publickey https://www.publickey1.jp/blog/12/_1040.html 74
Slide 75
Slide 75 text
自動改札機の運賃計算プログラム 10の40乗のパターンのテスト = 膨大な組み合わせを 見落としなくテストする ための仕組み 75
Slide 76
Slide 76 text
小話 76
Slide 77
Slide 77 text
→ → 77
Slide 78
Slide 78 text
→ → ペンギンテストです 78
Slide 79
Slide 79 text
おさらい 79
Slide 80
Slide 80 text
● ユーザー影響を出さずに ● 本番環境で ● 実際のユーザーデータを使って 検証するオリジナルの手法 ペンギンテストとは 80
Slide 81
Slide 81 text
2. 安全のための「ペンギンテスト」 🐧 ペンギンテストの 概要 🐧 ペンギンテストの 仕組み 🐧 ペンギンテストで直⾯した 問題 ✔ 81
Slide 82
Slide 82 text
82 超抽象化した サンプルコードで お話しします
Slide 83
Slide 83 text
83
Slide 84
Slide 84 text
84 ① テスト対象の 新ロジックを実行 (※ifの部分は後述)
Slide 85
Slide 85 text
85 ① テスト対象の 新ロジックを実行 処理結果は 値オブジェクトに 退避する
Slide 86
Slide 86 text
86 ② 旧ロジックを実行 結果はDBに保存 (既存処理)
Slide 87
Slide 87 text
87 ③ 新旧の結果を比較 ログに出力
Slide 88
Slide 88 text
88 ③ 新旧の結果を比較 → 新旧の処理結果に差異がない場合 → その旨をログに出力
Slide 89
Slide 89 text
89 ③ 新旧の結果を比較 → 新旧の処理結果に差異がある場合 → バグの可能性あり!差異の中身をログに出力
Slide 90
Slide 90 text
90 ④ ペンギンテスト中の FATALは握りつぶす (※後述)
Slide 91
Slide 91 text
91 ⑤ 差異の有無に関係なく 処理結果は旧処理の ものを採用する
Slide 92
Slide 92 text
92 ⑤ 差異の有無に関係なく 処理結果は旧処理の ものを採用する 新処理の結果は 比較が終わったら 捨てる
Slide 93
Slide 93 text
93 ⑥ 既存の旧処理の 続きに戻る
Slide 94
Slide 94 text
つまり ユーザーの運用にテストをさせる検 証手法 94
Slide 95
Slide 95 text
本番環境で実際のユーザーデータを使用 ↓ ユーザーがいつも通り使っているだけで 現在使われているパスを勝手に通るので 見落としのない検証が可能 95
Slide 96
Slide 96 text
本番環境で実際のユーザーデータを使用 ↓ ユーザーがいつも通り使っているだけで 現在使われているパスを勝手に通るので 見落としのない検証が可能 96 ここも ポイント
Slide 97
Slide 97 text
カバレッジ100%を目指す 「今」使われているところの 正しさを担保する 97
Slide 98
Slide 98 text
カバレッジ100%を目指す 「今」使われているところの 正しさを担保する ↓ 今のプロダクトの価値を担保する 98
Slide 99
Slide 99 text
類似のテスト手法 シャドーテスト 99
Slide 100
Slide 100 text
アプリケーションのデプロイとテスト戦略の種類 by Hikaru さん(Zenn) 100 https://zenn.dev/hi_ka_ru/articles/deploy-test-pattern-20240513
Slide 101
Slide 101 text
アプリケーションのデプロイとテスト戦略の種類 by Hikaru さん(Zenn) 101 https://zenn.dev/hi_ka_ru/articles/deploy-test-pattern-20240513 シャドーテスト
Slide 102
Slide 102 text
アプリケーションのデプロイとテスト戦略の種類 by Hikaru さん(Zenn) 102 https://zenn.dev/hi_ka_ru/articles/deploy-test-pattern-20240513 ペンギンテスト
Slide 103
Slide 103 text
シャドーテストの メリットを享受 103
Slide 104
Slide 104 text
104 デメリットは排除
Slide 105
Slide 105 text
しかし 105
Slide 106
Slide 106 text
本番環境を使う = その分 問題もあった 106
Slide 107
Slide 107 text
2. 安全のための「ペンギンテスト」 🐧 ペンギンテストの 概要 🐧 ペンギンテストの 仕組み 🐧 ペンギンテストで直⾯した 問題 ✔ ✔ 107
Slide 108
Slide 108 text
ペンギンテスト 最大のポイント ユーザー影響を出さずに 本番環境でテストができる 108
Slide 109
Slide 109 text
ペンギンテスト 最大のポイント ユーザー影響を出さずに 本番環境でテストができる 109 ココ
Slide 110
Slide 110 text
いかにユーザー影響を 排除するか 110
Slide 111
Slide 111 text
【問題①】 ペンギンテスト内部のFATAL 111
Slide 112
Slide 112 text
【問題①】ペンギン内部のFATAL ● ペンギンテスト内部で考慮不足 → FATALが発生 ○ 絶対に止めないためのペンギンテストなのに 処理が止まってしまう ● 実はこれで一度小さな障害を起こしている ○ 常時監視のおかげですぐ気付けた 112
Slide 113
Slide 113 text
【対処方法①】 FATALは検知しつつ握り潰す 113
Slide 114
Slide 114 text
【対応①】FATALは検知しつつ握り潰す ● 考慮漏れによるFATALが発生しても止めない ○ あえてThrowableで握り潰す ○ いわゆるフォールトマスキング ● もちろん握り潰して終わりではない ○ ログは出力するので、ユーザー影響を出さずに 後でゆっくり調査することができる 114
Slide 115
Slide 115 text
【対応①】FATALは検知しつつ握り潰す ここで検知されたFATAL = ペンギンテストをせずに出してたら 障害になっていたもの → 考慮漏れを徹底的に潰す 115
Slide 116
Slide 116 text
【問題②】 処理量増加によるメモリの枯渇 パフォーマンスの悪化 116
Slide 117
Slide 117 text
【問題②】メモリとパフォーマンス ● 処理量が一時的に2倍 ○ ペンギンテストは新旧ロジックの比較をする ○ 最初はトラブルが続出 ■ CPUが張り付いて処理が超遅くなったり ■ メモリが溢れたり ○ インフラ部署と連携、常時監視とアラート 117
Slide 118
Slide 118 text
【対処方法②】 ペンギンテストの実施率と稼働時間を コントロールをしつつ パフォーマンス改善をする 118
Slide 119
Slide 119 text
【対応②】当選確率と稼働時間を制限 ● 前提 ○ 常時稼働処理 ○ 失敗しても次で成功すれば許容 ○ = 失敗し続けることを防げればそれでヨシ 119
Slide 120
Slide 120 text
【対応②】実施率と稼働時間を制限 ● 当選確率をコントロール ○ ペンギンテスト実施率を制御 ○ 最初は1/1000から、徐々に上げて最終的には100% ● 稼働時間を指定 ○ 最初は平日の10:00-17:00のみ稼働 ○ 安定した後、24時間営業に切り替え 120
Slide 121
Slide 121 text
121 if (isPenguinTestUser()) で 平日 10:00-17:00のみ ペンギンテストを実施する
Slide 122
Slide 122 text
122 ifを通らなければ既存処理と全く同じ 有事にすぐ対応できない時間は 既存処理を通すように制御
Slide 123
Slide 123 text
【対応②】同時にパフォーマンス改善 本番環境の負荷で実測値を見たからこそ 検知できたエッジケース = ペンギンテストをせずに出してたら 障害になっていたもの → パフォーマンス面の考慮漏れを徹底的に潰す 123
Slide 124
Slide 124 text
2. 安全のための「ペンギンテスト」 🐧 ペンギンテストの 概要 🐧 ペンギンテストの 仕組み 🐧 ペンギンテストで直⾯した 問題 ✔ ✔ ✔ 124
Slide 125
Slide 125 text
なんやかんやで 稼働が安定したら 125
Slide 126
Slide 126 text
ここからがペンギンテストの本番 126
Slide 127
Slide 127 text
潰します 127
Slide 128
Slide 128 text
ペンギンどもを 128
Slide 129
Slide 129 text
129
Slide 130
Slide 130 text
ひたすら障害の芽を潰す ● デバッグ大会 ○ ログに出力された差異を見ながらひたすらデバッグ ○ 差異ログ=考慮漏れを「ペンギン」 考慮漏れ潰しを「ペンギン潰し」と呼んでいた ● ペンギンを潰す → 当選確率を上げる の繰り返し 130
Slide 131
Slide 131 text
[ マネージャー ] チームでは日夜 party🐧🤛 が開催 131
Slide 132
Slide 132 text
ペンギン撲滅に約半年 ● 時間がかかった要因 ○ 初めての検証方法で手探りだった ○ パフォーマンスの改善に時間がかかった ○ 偽陽性に悩まされた ■ ファントム(幻)ペンギンと呼んでいました 132
Slide 133
Slide 133 text
多種多様なペンギンがいた 133
Slide 134
Slide 134 text
ペンギン撲滅に約半年 ● 障害の芽を見分ける ○ どれが潰すべきペンギン=考慮不足で、 どれは偽陽性のペンギンなのか、 振るい分けるのに時間がかかった 134
Slide 135
Slide 135 text
実際にやってみて ペンギンテストのメリット 135
Slide 136
Slide 136 text
ペンギンテストのメリット ● リリース後の障害、バグが本当にゼロ! 136
Slide 137
Slide 137 text
ペンギンテストのメリット ● リリース後の障害、バグが本当にゼロ! ● 思い切った設計変更ができる ○ デザインパターンの導入 137
Slide 138
Slide 138 text
ペンギンテストのメリット ● リリース後の障害、バグが本当にゼロ! ● 思い切った設計変更ができる ○ デザインパターンの導入 ● 気軽にパフォーマンス改善ができる ○ 気軽に実測値を取れる ○ 300秒のクエリが0.8秒に! 138
Slide 139
Slide 139 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 139
Slide 140
Slide 140 text
ペンギンを潰し切ったら 140
Slide 141
Slide 141 text
おしながき 安全に倒し切った 背景と課題 安全に倒し切るための「ペンギンテスト」 ペンギンテスト後 その他の安全対策 1 2 3 ✔ ✔ 141
Slide 142
Slide 142 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト →ロジックの正しさを担保 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 142
Slide 143
Slide 143 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 143
Slide 144
Slide 144 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 144
Slide 145
Slide 145 text
手動検証 ● 事実上の結合テスト ○ 画面から一連の流れを実施する ● と同時に 145
Slide 146
Slide 146 text
146 もともとの目的 リプレイスのwhyは スパゲッティコードの 改善ではない
Slide 147
Slide 147 text
147 リプレイスのwhyは 新機能をユーザーに 提供すること
Slide 148
Slide 148 text
手動検証 ● 事実上の結合テスト ○ 画面から一連の流れを実施する ● 新機能の検証 ○ ペンギンテストでは通していないパス 148
Slide 149
Slide 149 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 149
Slide 150
Slide 150 text
カナリアリリース ● 新機能の先行公開 ○ 条件をもとに選定した一部ユーザー ■ 新機能への興味 ■ 平均リクエスト数 ○ 1週間ほどモニタリングして様子見 150
Slide 151
Slide 151 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 151
Slide 152
Slide 152 text
ダークローンチ ● ここでは、新機能のリリースを こっそり一部のユーザーにだけ行うこと(諸説あり) ● 3週間かけて段階的にリプレイス ○ 大規模な障害を避ける目的 ○ 全ユーザーをリスク順に 15グループに分けて リスク小順にダークローンチ 152
Slide 153
Slide 153 text
安全に倒し切るリリース 1. 実装完了 2. ペンギンテスト 3. 手動検証 4. カナリアリリース 5. ダークローンチ 6. UIリリース 1 2 3 4 5 6 153
Slide 154
Slide 154 text
UIリリース ● ユーザーへの価値提供 ○ 新機能の設定画面を公開 ○ 全ユーザーが新機能を使えるように 🙌 154
Slide 155
Slide 155 text
おしながき 安全に倒し切った 背景と課題 安全に倒し切るための「ペンギンテスト」 ペンギンテスト後 その他の安全対策 1 2 3 ✔ ✔ ✔ 155
Slide 156
Slide 156 text
まとめ 156
Slide 157
Slide 157 text
手法を組み合わせて レガシーシステムを 障害0でリプレイスに成功 157
Slide 158
Slide 158 text
ペンギンテストは 「俺の考えた最強検証メソッド」では ない 158
Slide 159
Slide 159 text
当時の私たちがとれた ベストな現実解に近いもの 159
Slide 160
Slide 160 text
しかし 160
Slide 161
Slide 161 text
ペンギンテストで 15年物のレガシーシステムを バグ0で作り替えられたのも また事実 161
Slide 162
Slide 162 text
いま同じような壁に 直面している方へ 162
Slide 163
Slide 163 text
● この発表をtipsやインスピレーションとして 使えるところは採⽤して、⾊々な形に合った 「安全に倒し切ったリリース」があると良い ● 安全なリリースのための選択肢の⼀つと なりますように 🙏 GOAL & NOT GOAL 163
Slide 164
Slide 164 text
ご静聴 ありがとうございました 164