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