
この記事は、10X 新春ブログリレー 2026の記事です。前日は、jojoさんによる「バージョンアップ手作業のつらみから解放された4つの自動化施策」でした。自動化って尊い!
もう1月中旬!早いですね。 id:hisaichi5518 です。
2025年は、Stailer ネットスーパーの店内業務・配達用アプリのリアーキテクチャに伴う作り直しを主に進めていました。特に店舗で注文された商品を集めるときに利用するピッキングリストというStailer ネットスーパーを利用する小売企業のほとんどが利用する部分の作り直しを行いました。
この作り直しを"攻めた開発"として、安全安心なリリースとの両立を強く意識して進めていたので、それについて書きます。
なぜ安全安心なリリースが必要なのか?
Stailer ネットスーパーの店内業務・配達用アプリは、注文された商品を集める(ピックする)ときに利用する機能や配達に関する機能などを持っています。多くの小売企業がこの機能を利用しており、1日にたくさんの注文がこのアプリを通じて処理されています。
そのアプリでもし不具合が発生したら
- 店舗スタッフの業務が遅延*1
- お客様への配達が遅延
- お客様・店舗からの問い合わせが殺到
つまりネットスーパーを利用するお客様の食卓はもちろん、小売企業の生産性、10Xの生産性、間接的には売上など影響が大きいです。なので、安全安心なリリースをしていく必要があります。
安全安心なリリースをするために
安全安心なリリースは、以下を満たすものだと考えています。
- なるべく早く開発チームが問題に気付くこと
- リリース後よりはリリース前、実装後よりは実装前などなるべく早いことが望ましい
- リリース後に問題があったら1分1秒でも早く元に戻せること
- リリース後に問題があったら1分1秒でも早く原因を特定できること
これらを満たすためにやっていることを書いていきます。
機能が持つ概念をまとめる
今回の作り直しでは、ただ機械的に既存実装を新しいアーキテクチャに置き換えていくというよりは、改めて「この機能はどういう概念を持っているか」をDesign Docに書いてから実装しています。例えば「商品のバーコードを読み取ってピックしたことを記録する」という機能を扱う時、以下のように捉えました。
- 読み取る
- Android は 内蔵カメラを使ってバーコードを読み、 MLKitを利用してバーコードを読み取る
- iOS は内蔵カメラを使ってバーコードを読み、AVFoundationを利用してバーコードを読み取る
- 外付けスキャナは外付けカメラを使ってバーコードを読み、外付けスキャナ独自の方法でバーコードを読み取る
- 変換する
- AVFoundationは、12桁のバーコードを読み取った時、13桁に自動的に変換する。Stailer的には、12桁として扱いたいので13桁かつAVFoundationで読み取りかつ最初の桁が0の場合は、12桁に変換する
- 処理する*2
- アプリ内に保持されたリストの中から読み取ったバーコードに一致するものを見つけて、結果によってピックを記録する
「商品のバーコードを読み取ってピックしたことを記録する」は、1.読み取る, 2.変換する, 3.処理するによって構成されており、1, 2, 3はそれぞれが疎結合になっているべし!というのが整理することで見えてきます。
このあたりを整理せずに実装し始めると、既存実装に引っ張られて密結合した状態の実装が出来上がって残念なことになるみたいなことがありました。
整理した内容はDesign Docに記載して、実装前にQAE, SWEにレビューしてもらっています。
実装時に何を検討するかを書く
またDesign Docには「より詳細な設計をする実装時に何を検討するか」も書いていています。
例えば、「商品のバーコードを読み取ってピックしたことを記録する」という機能を整理した結果、1.読み取る、2.変換する、3.処理するというのがあることがわかりました。また読み取る部分では複数の読み取り方法があり、今後も新しい読み取り方法が追加されうることがわかりました。
そこで「バーコード読み取り方法の追加にはどのように備えておくか?」という疑問が出てくるのですが、これはクラス設計など詳細設計時に色々試しながら決めたいので、それは未確定の論点としてDesign Docに記載しておき、プルリクエストを出すときに一緒にDesign Docに結論を追記してレビューを依頼するとしています。
実装前にリリース計画と切り戻し方法を書く
実装前にリリース計画をDesign Docにまとめていて、そこに問題が起きた時どうやって切り戻すかを書いています。実装してから切り戻し方法を考えるよりは、実装する前に考えておくとそれを踏まえて作るので後から継ぎ足しにならないので考えることが少なくていいです。
自動テストを書く
今までテストが書けてなかったのがリアーキテクチャによって書きやすくなったので書くようになりました。単体テストとWidgetテスト(ゴールデンテスト)を書いています。
意味のあるテストであることが重要だと思っていて、QAEが行ったテスト設計を元に単体テストを書き足したりすることもあります。またあえてテストを書く作業を見積もり時に考慮していて、実装は2ポイントテストはその半分くらいの作業量だからこのチケットは3ポイントみたいなことを見積もり時に考えています。
本番に近いデータで単体テストする
商品に付いてるバーコードをアプリで読み取ってピックを記録するいう機能があるのですが、バーコードは様々なデータがあり標準的なパターンだけではなく小売企業が独自に定義したパターンもあったりするので、本番に近いデータを利用して単体テストを動かすことで知らなかったパターンを見つけたり、作り直す前と後で動作に予期しない変化がないことを確認しています。
しかし、店頭に並んでいる実際の商品のバーコードはStailerは持っておらずわからないので、あくまで実際にスキャンするバーコードに近いだけであるというのは念頭においておく必要はあります。
シャドウテストをする
特定のリストから条件によってデータを抽出するというような表示や直接データ変更を行わないロジックはシャドウテストを行うようにしています。
シャドウテストは、本番環境で新旧両方の実装を並行して動かし、新しい実装の結果を実際には使わずに記録・比較するテスト手法です。ユーザーには旧実装の結果だけが返されるため、新実装に問題があってもユーザー影響はゼロで、本番の実データで新実装を検証できるのが最大のメリットです。
シャドウテストを行ったおかげで既存実装と作り直し後の実装で動作に差異があることがわかり、事前にプロダクトマネージャーに「リリース後、こういう変化があります。これは新しい実装が仕様に沿っているので正しい変化です」というコミュニケーションが取れて、リリース後にドタバタせずに済みました。
Feature Flagで機能の有効無効を切り替える
モバイルアプリはリリースするのにも審査などで早くても1日くらいかかるので、Feature Flagで機能の有効無効を切り替え出来るようにしてリリースして、有効後に安定していると判断できたらFeature Flagの利用をやめるようにしています。問題が合ったときは、Feature Flagをオフにするだけで切り戻しが高速に行えます。
調査用のログを出す
とにかくログを出して問題が起きてそうな時に何が起きてるのかを把握できるようにしています。何をログとして記録するかがポイントだと思いますが、自分は以下を意識して記録するようにしています。
- いつ
- 誰が
- 何が起きたか
- 変化がある場合は、変化前と変化後の値
- 異常がある場合は、なにが異常で異常とした根拠
一方でこのログはあくまで不具合の調査用です。分析用のログは極力サーバーサイドで記録するべきです。「A画面を開いた」など分析用にどうしてもモバイルアプリ側で記録する必要があるときは、別の仕組みを利用しています。
DataDog RUMに記録出来ることは記録する
Datadog RUMは以下のようなイベントを記録できます。これらを取ることで今までは時間がかかっていた調査もかなりスムーズにできるようになってきました。
- ユーザーが表示したビュー / Dialog
- タップイベントなどのユーザーアクション
- エラー
- APIリクエスト
- Feature Flagの値
- Shared Preferencesの値
今のところセッション数の制御はしておらず、toCサービスに比べてセッション数が多くならず突然跳ねることもないので、今はとにかく全て送るとしています。
モニタリングを行う
クラッシュ率、このログが大量に出たらアラートなど色々モニタリングしてます。 この辺りはRUMとログをDatadogに送っているので、Datadogで行っています。
俺たちの戦いはこれからだ!
安全安心なリリースのためにやれることはやり尽くしたように見えますが、作り直すこと以外も含めて攻め続けるにはまだまだやれることはあるはずです。例えば
- APIリクエストはエラーによってはリトライが行われるがそれを考慮したモニタリングにはなってない。または考慮できていないため意味のあるモニタリングになりにくい。SLO化もまだ
- ピックにかかる時間を監視して、一定の基準以上遅くなればアラート
- E2Eテストがなく人間による手動の結合テストが必要
2026年も引き続き、攻めの開発と安全安心のリリースの両立をしていきたいと思います!!明日は、uraさんによる「仮)登壇資料をAIに作らせたら失敗した話」です。楽しみですね!