ファントムペンギンにダマサれるな! 15年物のレガシー機能を本番のユーザーデータで検証してリプレイスする「ペンギンテスト」とは?のトップ画像

ファントムペンギンにダマサれるな! 15年物のレガシー機能を本番のユーザーデータで検証してリプレイスする「ペンギンテスト」とは?

投稿日時:2025/05/07 23:30
巻嶋 雄大のアイコン

NE株式会社 / チームリーダー / アプリケーションエンジニア / 開発部

巻嶋 雄大

Xアカウントリンク
櫻井 思寧のアイコン

NE株式会社 / 開発部

櫻井 思寧

Xアカウントリンク

クラウド型ECプラットフォーム「ネクストエンジン」を提供するNE株式会社では、拠点ごとに在庫を管理する機能を2023年にリリース[1]して継続的に改善してきました。とくに2024年11月のリリース [2]では、15年物のシステムをフルリプレイスするという想定外に大きなプロジェクトになりましたが、開発チームはこれをリリース後の障害ゼロで乗り切りました。

その実現において採用した手段の1つが「ペンギンテスト」というユニークなテスト手法です。新ロジックを開発し、本番環境にデプロイし、旧ロジックと同時に新ロジックにも本番データを流し込んで出力を比較する。異なっていたらエラー、すなわち「ペンギン」と見なして調査し、新ロジックを修正する。このプロセスを繰り返してエラーを潰していきます。NE株式会社でプロジェクトを推進した巻嶋雄大さんと櫻井思寧さんに、リプレイスの状況やテスト手法の仕組みを聞きました。

レガシーで密結合なコア機能が機能拡張の妨げに

── ネクストエンジンは2007年に開発された注文管理システムで、現在では契約企業が約6,500社と多くのユーザーを抱えるサービスです。どのような体制で開発しているのでしょうか?

櫻井 ネクストエンジンの開発組織では、約20人のエンジニアが4つのチームに分かれて開発と保守を行っています。私は、巻嶋さんがプロジェクトリーダーを務めるチームに所属して、拠点管理機能の開発に携わりました。

── 拠点管理の機能開発にあわせて、ネクストエンジンに3つあるコア機能のうち「在庫連携」と「引当」の2つをリプレイスしたそうですが、システムの大半を書き換えたことになるのでしょうか。

櫻井 いえ、ネクストエンジンには大小200以上の機能がありますから、コードの量でいえばそれほどでもありません。ただ、最もコアとなる機能ですから絶対に止めてはいけませんし、プロダクトで最も古く15年前から大きく手を入れられることなく動作していて、ソースコードは複雑に絡み合っている状態。1カ所の変更が他のさまざまな機能に影響を及ぼす懸念もありました。

巻嶋 いわゆる密結合の状態ですね。以前からリファクタリングの必要性を感じており、社内でもたびたび問題提起していましたが、影響範囲の大きさからずっと先送りになってきました。しかし、あまりに密結合過ぎていよいよ機能追加がつらくなったことから、ようやく全面的に書き直すことになりました。

櫻井 拠点管理の機能追加は、私が開発部に異動してきた直後に始まった3年越しのプロジェクトです。構想自体は以前からありましたが、対象箇所は複雑に絡み合って影響範囲も大きかったため変更を加えてこなかった部分でした。それを今回は機能を分割して段階的に強化することで、2024年3月のリリース[3]までは大きく手を加えなくても実現できました。

── そこまでは開発できたものの、最後に取り掛かる機能追加では難しかったということですね。

櫻井 それまで巻嶋さんが「リプレイスした方がいい」と訴えるのを、周囲の私たちは「いやいや、そんなリスクの大きいことできません」と反対してきましたが、どうしても最後には(出荷拠点の管理と関係の深い)在庫連携や引当のコードに手を入れる必要がある。だけど触るに触れない。いよいよ巻嶋さんの言うことが正しいんじゃないか。ということで、インフラチームやCSも巻き込んでリプレイスを実施することになりました。

開発チームの集合写真
▲ NE株式会社内で打ち合わせをする拠点管理機能開発チーム

完全なテストケースでなく実際に使われる範囲をスコープに

── 絶対に止められないコア機能をリプレイスするにあたって、レガシーな旧ロジックを置き換える新ロジックに問題がないことを「ペンギンテスト」という手法で確認したということですが、網羅的なテストケースを作成する通常の手法を用いなかった理由は何でしょうか。

櫻井 今回の機能では、影響を与える変数が非常に多いという特徴がありました。例えば「引当」処理では在庫数はもちろん、送り先の住所も影響しますし、予約商品か通常商品でも違ってきます。入力の組み合わせを洗い出して要素ごとの影響を検証しようとすると、テストケースが爆発的に増えてしまいます。たとえテストが書けたとしても、大き過ぎて誰にもメンテナンスできない負の遺産になるのは明らかでした。

巻嶋 一番困難だったのは、データが動的に変わってしまう点です。郵便番号と住所のように一対一のマッピングであればテストを書くのは容易ですが、ネクストエンジンでは膨大な量の入力値を組み合わせて、1億レコード以上あるデータベースをもとに結果を算出することがあるので、その膨大なテストケースを用意するのは不可能に近いですね。

そこで、想定される条件を完全に網羅するのではなく、現状でお客様が使っている条件を網羅することを目指しました。お客様が「今」使われている範囲であれば問題は起きない、という状態を目指したのです。

── それで新ロジックに「本番データを流し込む」テストを実施したのですね。NE株式会社の開発ブログの記事によると次の仕組みになっています[4]

  1. 旧ロジックを実行
    ----- ここからペンギンテスト -----
  2. 新ロジックを実行
  3. 新旧の結果を比較
    • 新旧の結果に差異がない場合:差異がない旨のログを出力
    • 新旧で結果が異なる場合:ロジックが間違っている可能性があるので、差異がある旨と差異の中身(どう異なるか)をログに出力
  4. 差異があろうがなかろうが、採用されるのは旧処理とする(新処理の結果は捨てる)
    ----- ペンギンテストここまで -----
  5. 旧処理の続きに戻る

NE株式会社の開発ブログ「安全に倒し切るリリースをするために:15年来のレガシーシステムのフルリプレイス挑戦記」より

本番環境で同じ処理を新旧ともに実施し、全ての入力を比較することで「お客様が使っている」条件を網羅する考え方だと思いますが、特別な条件の処理が月末や年度末などで発生したりしないのでしょうか。

櫻井 引当は2〜3分に1回、在庫連携は5分に1回のバッチ処理で、ずっと数分間隔で動いている処理ですし、時期に依存するロジックもとくにありません。

巻嶋 ペンギンテストはおそらく、同じような入力が大量に続く処理に向いているのではないかと思います。時期による偏りがある処理では、また違う手法を考える必要があるかもしれません。

ペンギンの量をコントロールしながらエラーを潰す

── 新ロジックを旧ロジックと同じ本番環境にデプロイすることが特徴だと思いますが、本番環境でテストすることによる弊害はなかったのでしょうか。

櫻井 新ロジックでFATALエラーが発生すると全体が止まるので、握り潰すようにしました。ペンギンテストの仕組みそのもので不具合を出してしまったこともありましたが、監視していたのですぐに気付けました。

ただ、旧新両方のロジックを通すと処理が2倍になるため、処理時間も長くなります。引当処理に時間がかかると、在庫数より多く売ってしまう「売り越し」のリスクが高くなる問題もありました。また、ペンギンテストを開始した直後には膨大な「ペンギン」が出力されてとても対応しきれなかったので、ペンギンテストを実施する確率と時間帯を調整しながら、ペンギンの量をコントロールしていました。

── ペンギンの量という表現は面白いです。ペンギンテストはインスパイアもとになったテスト事例に由来する命名ですが[5]、エラー(新旧ロジックの結果の差異)そのものがペンギンと呼ばれるんですね。

巻嶋 ペンギンテストのログはモニタリングツールで監視していましたが、文字列で「ERROR」と出力しても埋もれてしまうので、ペンギンの絵文字を付けて抽出しやすくしました。画面上でも目立って面白かったですね。

ペンギンテストの出力 NE株式会社の開発ブログ「安全に倒し切るリリースをするために:15年来のレガシーシステムのフルリプレイス挑戦記」より

櫻井 エラーの原因ごとに異なる絵文字を使ったり、ペンギンのほか「ふくろう」や「ひよこ」を表示したりしていました。冒頭を絵文字にすると、パッと見て「どんなエラーなのか」が分かるのはよかったですね。かわいいだけでなく、文字なのでログも検索できますし。

巻嶋 これまでにペンギンをどのくらい減らせたのかも、モニタリングツールのグラフで可視化して視覚的にも分かりやすく確認できました。私自身も安心感がありましたし、マネージャーや他チームに報告する材料にも利用できます。

── ペンギンの量を具体的にどのように調整したのでしょうか。

巻嶋 新ロジックは抽選で当選したときだけ実施するようにして、この当選確率を調整しました。引当も在庫連携も冪等性のあるバッチなので、万が一失敗してしまっても後続のバッチでリカバリが可能です。テストを通す確率をコントロールすることで、リスクコントロールを行いました。

櫻井 最初は1000分の1という確率でした。そこで出たペンギンを確認して、新ロジックの間違いを修正するとペンギンが減っていきます。おおむね潰せてパフォーマンスにも問題がなければ、次は500分の1にします。するとまたペンギンが増えるので、同じように新ロジックを見直します。ロジックの修正だけでなく、時間がかかり過ぎるならパフォーマンスも改善しなければいけません。繰り返しながら、10分の1、5分の1、3分の1、2分の1と当選確率を上げていきました。

── さきほどテストを実施する時間帯も調整したということでしたが。

櫻井 最初は何かあってもユーザーが問い合わせできるよう、サポートセンターが開いている平日の午前9時から午後5時までだけ動かしていました。営業時間に発生したエラーを「昼ペンギン」と呼んでおり、これが落ち着いたら24時間回すようにしました。すると今度は「夜ペンギン」が現れます。

巻嶋 ECサイトの利用は、夜の方が購入者も帰宅してスマートフォンを自由に操作できるので日中より活発だという特有の事情があります。そのため、夜間のペンギンテストを最初のうちは避けていました。結果として夜特有のエラーはありませんでしたが、数としては夜の方が多かったですね。

エッジケース・パフォーマンス・偽陽性

── 特定のお客様でしか発生しないようなエッジケースはどのくらいあったのでしょうか。

巻嶋 修正すると大きく減るペンギンと、あまり変わらない「外れペンギン」は半々くらいだったでしょうか。1日に何万という単位でペンギンが現れますが、根本的な要因を潰せれば一気に減ることもあります。1つの問題を解決するだけで一気に5,000件も減ったりすると気持ちいいですね。

櫻井 逆に「これは大きなペンギンだろう」と思っていたのにエッジケースで、肩透かしになることもあります。ペンギンが出現する要因はまとめると20種類ほどでしたが、トータルで潰したエラーの数は数え切れません。パフォーマンスを改善したりエッジケースに対応したりすると、さっきまでいなかったペンギンが現れるような「いたちごっこ」になることもありました。

── パフォーマンス改善というのは、先ほども話題に出た新ロジックが遅いことの対応でしょうか。

櫻井 今回のリプレイスではアーキテクチャなどはもとのままですが、この機会にデザインパターンの導入とあわせて、パフォーマンスをもう少し高めようと旧ロジックでデータベースアクセスのボトルネックになっていた箇所を改善しています。

巻嶋 一件一件逐次処理していた旧ロジックを、一括でまとめて処理するように変更しました。主にクエリの発行回数を減らし、適切なインデックスを利用するという2点ですね。

── それはどのくらいの効果があったのでしょう。

巻嶋 効果が一番あったところでは、300秒かかっていた処理が0.8秒になりました。これだけインパクトがあれば、協力してくれたCSやインフラチームにもよろこばれますね。

櫻井  ただ、パフォーマンス面でもお客様特有のエッジケースがありました。ほぼ全てのお客様は速くなるのに数社だけ逆効果になることもあり、どこまで対応するかは悩みどころでした。

巻嶋 私たちが想定していないデータの持ち方をしていて、インデックスが効かないケースですね。そこはもう、全企業が高速になるSQLを考えに考え続けて、最終的に300行あるSQLを書きました。

櫻井 私は「これレビューして」と言われて「なんすか、これ」って言ってしまいました。それだけで社内のエンジニアミートアップでライトニングトークができましたね。

── 変更が大きいと新しいペンギンが現れることもありそうですね。

巻嶋 むしろ「ここは問題がありそう」という不安な箇所で問題は起こらず、逆に「そこは大丈夫だろう」という箇所ほど問題が起きるんですよね。たまにパフォーマンスは改善できたものの、ロジック的に問題が生じることもありました。ただ、それもペンギンテストで見つけられるので、わりと気楽に手を入れることができますね。

櫻井 やってみなければ分からないことも多いパフォーマンス改善ですが、ペンギンテストのおかげで気軽に実測値が取れたのはよかったですね。

── ペンギンテストに関連した対応で時間がかかってたいへんだったことは何でしょう。

巻嶋 いろいろありますが、一番大きかったのは偽陽性の調査です。当初は単純に、新ロジックと旧ロジックの結果を比較して全部一致させればOKだと考えていたのですが、意外と「一致していなくていい」パターンもあったのです。ただ、一致していなければエラーになってしまうので、このペンギンは一致していなければいけないのか、それとも一致していなくてもいいのかを、本来あるべき処理に立ち返って区別するのに2ヶ月くらい時間が取られました。

── そもそも旧ロジックの仕様やドキュメントは残っていたのでしょうか。

巻嶋 ありません。リバースエンジニアリングして作成したフローチャートをもとに実装し直しました。

櫻井 古いコードですから、読み解いてみたら不具合だったということもありました。もちろんそういったコードは適切に修正するのですが、それをペンギンテストすると、結果が一致していないのでペンギンが出ます。こうした偽陽性を「ファントムペンギン」としてマークして避けながら、直すべき場所は直すという活動も同時に行いました。

開発組織によいサイクルが生まれている

── 当初は拠点管理の最後の機能開発とそれにともなうコア機能のリプレイス、それからペンギンテストもあわせて、2024年4月からいつごろまで実施する予定だったのでしょう。

櫻井 8月くらいには終わる予定でした。実際は拠点管理機能に一区切りつけたリリースが2024年11月なので、半年くらいかかりました。

── ペンギンが多過ぎて時間もかかり過ぎているからもうやめようという話にはならなかったのでしょうか。

櫻井 途中でやめようという話はありませんでした。というのも、大きな要因を1つ潰すとペンギンをたくさん減らせて、そのたびに「ああ、これに気付けてよかった」という瞬間が訪れます。それも継続的に。もしペンギンテストがなかったらこのエラーを気付かずリリースして大障害になっていたかもしれない、ということも大小さまざまあったので、やっておいてよかったということは多々あります。

巻嶋 初めての取り組みだったので、想定工数が誤っていたという感覚ですね。

櫻井 きつい半年間でしたがやってよかったと思います。社内的にも、この機能は主要機能であり「納期よりも品質重視、安全重視で安全に倒しきってほしい」と言われていたため、私たちとしても「自信を持ってエラーを潰しきりましたから、これで出せます」と言えるまで、ゴーを出しませんでした。

── 結果として、本番リリース後は問題はありませんか。

巻嶋 幸運なことに、不具合はゼロです。

櫻井 社内からも「これを不具合ゼロでやりきったのはすごい」と評価してもらえています。またペンギンテストの過程で、私たちの想定していない使い方をしているお客様や、これまで知らなかった機能を知ることができて、プロダクトそのものに対する理解も深まりました。

── ペンギンテストは、どれくらい汎用的に利用できる手法だと考えていますか。

櫻井 ちょうど別のプロジェクトでも「ペンギンテストをやろうか」という話が持ち上がっています。今度はもっときちんとした工数を見積もって進められると思います。

ただ、今回はプロダクトをリプレイスするために「ペンギンテスト」という新しい手法を取り入れましたが、決して手法を試すこと自体が目的ではありません。あくまでお客様に価値を提供することが重要で、そのため必要だったから実施したまでです。

巻嶋 この手法だけではなく、お客様に少しでも速く価値提供するために開発プロセスを改善したり、開発メンバーも柔軟にさまざまなことを試すようになっています。今回の手法で成功できたのは、開発組織によいサイクルが生まれているからだろうと思っています。

── さらなる機能改善に期待しています。本日はありがとうございました。

開発チームの集合写真2


取材・構成:高橋 睦美
編集・制作:はてな編集部

脚注
  1. 参照:NE株式会社「拠点管理機能をリリースしました

  2. 参照:NE株式会社「EC運営をもっと自由に!ネクストエンジンの「拠点管理機能」アップデートで物流の未来を加速

  3. 参照:NE株式会社「配送コスト削減と顧客満足度向上を目指す新機能をリリース ~配送距離を最小限に抑える、拠点ごとの在庫管理を実現~

  4. 参考資料:櫻井さんがPHPerKaigi 2025で発表した「安全に倒し切るリリースをするために:15年来レガシーシステムのフルリプレイス挑戦記」でもペンギンテストの仕組みが紹介されています。

  5. ペンギンテストは、2012年にPublickeyに掲載された「自動改札機の運賃計算プログラムはいかにデバッグされているのか? 10の40乗という運賃パターンのテスト方法を開発者が解説(中編)」という事例をもとに、膨大なテストケースの検証を別のロジックで計算して突き合わせた点にインスパイアされており、この鉄道会社のIC乗車カードのキャラクターが「ペンギン」であることから命名されている。