同じ月の走行距離が2つの画面で違った — 不具合と決める前に、合計を分解してアカウントを突き合わせる
同じ10月の走行距離が、8分違いで撮った2つの画面で 192.6km と 187.2km。集計コードは、どちらも同じでした。
個人開発しているツーリング記録アプリで起きたことです。結論から書くと、集計の不具合ではなく、2つの画面が別々のアカウントのデータを見ていました。最初の仮説は外れ、決め手になったのはコードを読むことではなく、合計を分解して足し直すことでした。
実装と調査はAIに任せていて、筆者がしたのは画面を見て違和感を伝え、確認に答えたところまでです。アプリの開発経緯は開発記の第4話に、同じ統計画面で最高速度の出し方を見直した話はこちらの記事に書いています。
発端:8分違いの2枚で、同じ月の合計が違った
アプリの画面を撮り比べていて、数字が合わないことに気づきました。
13:16に撮った統計画面と、13:24に撮った月別レポートです。どちらも10月の走行距離を出しています。
| 項目 | 統計画面(13:16) | 月別レポート(13:24) |
|---|---|---|
| 10月の合計 | 192.6km | 187.2km |
| 10/3 のトリップ | 159.1km | 160.3km |
月の合計で 5.4km の差があり、同じツーリングを2台の端末で記録した 10/3 のトリップも値が違っていました。
まずコードを比べた:2つの画面は同じ集計をしていた
画面ごとに集計ロジックが違うなら、食い違いはそこで説明がつきます。最初に2つの画面の集計処理を比べてもらうと、どちらも同じ流れでした。
- トリップの一覧は、どちらの画面も
useTripsから取得する - そこから完了済みのトリップ(
completedTrips)だけを残す - 各トリップの
distanceKmを合計する - 表示時に小数1桁に丸める
丸め方の違いで 5.4km もずれることはありません。集計コードに差がない以上、違うのは入力のデータです。
ここで見落としていた事実が1つあります。useTrips が返すのは、いまログインしているユーザーのトリップだけです。ログインしているアカウントが違えば、同じ集計でも入力は別のデータになります。
最初の仮説「8分のあいだに保存値が変わった」は誤りだった
表を見ると、10/3 のトリップが 159.1km から 160.3km に変わったように見えます。撮影のあいだの8分で、保存済みの距離が書き換わったのではないか。未確定の記録の整理など、データ側の処理で値が変わることはあり得るので、最初はこれを疑いました。
ただ、10/3 は 1.2km 増えているのに、月の合計は 5.4km 減っています。10/3 の書き換えだけではこの組み合わせにならず、ほかのトリップも同時に変わったと考えないと説明がつきません。
結果として、この仮説は誤りでした。保存値は変わっておらず、2枚の画面は最初から別のトリップの集まりを見ていました。
合計を分解して、足し直して突き合わせた
仮説を当てに行くのをやめて、合計を分解しました。本番のデータを読み取り専用で1回だけ参照し、撮影時点までにあった10月のトリップをアカウントごとに足し直しています。
筆者の2つのアカウント(A と B と呼びます)の10月分を、10/3 とそれ以外に分けると次のとおりです。
| アカウント | 10/3 以外の10月分 | 10/3 | 合計 | 一致した画面 |
|---|---|---|---|---|
| A | 33.5km | 159.1km | 192.6km | 統計画面(13:16) |
| B | 26.9km | 160.3km | 187.2km | 月別レポート(13:24) |
どちらも画面の合計と小数第1位まで一致し、10/3 の値もそれぞれの画面と同じでした。2枚は最初から別のアカウントの数字を出していたと考えると、10/3 の差も月の合計の差も説明がつきます。
原因:同じ日の走行が、2つのアカウントに分かれて保存されていた
筆者はこのアプリに Google と Apple の両方でログインしていて、2つのアカウントはどちらも筆者のものです。2枚のスクリーンショットも、どちらも筆者の端末で撮りました。10/3 は、アプリのテストのために同じツーリングを2台の端末で記録していて、2台は別々のアカウントでログインしていました。
アカウントが違えば、useTrips が返すトリップも合計も違います。2つの画面の数字が違ったのは、仕様どおりの動きでした。
一般に起こり得ること(今回の原因とは別に)
Google と Apple のログインで別々のアカウントができることは一般に起こり得ますが、必ずそうなるわけではありません。
Firebase のユーザー管理のドキュメントでは、信頼できるプロバイダ同士でメールアドレスが同じ場合、アカウントが自動でリンクされることがあると説明されています。一方、Apple のプライベートメールリレーのドキュメントによると、利用者がメールを非公開にするとアプリにはリレー用のアドレスが渡るため、メールアドレスは一致しません。
筆者のアカウントが2つに分かれた条件は確認していません。上の説明は一般論で、今回の原因だとは言えません。
合計の一致から言えること、言えないこと
照合の結果は強い根拠ですが、証明ではありません。
| 区分 | 内容 |
|---|---|
| 言えること | 2つの画面の集計コードは同じ。各アカウントの10月分を足すと、それぞれの画面の合計と小数第1位まで一致した |
| 推定であること | どちらの画面がどちらのアカウントのものか。画面にアカウントの表示がなく、合計の一致から推定している |
| 未確認のこと | 10/3 の2つの記録が 159.1km と 160.3km に分かれた理由(推測で埋めずに残しています) |
| 未確認のこと | Google と Apple のログインで、アカウントが2つに分かれた条件 |
残った課題:どのアカウントを見ているか、画面から分からない
アカウントが違えば数字が違うのは当たり前です。問題は、どのアカウントでログインしているかが画面から分からないことでした。開発者の筆者でも、合計を分解するまで気づきませんでした。
利用者が同じことをすると、記録が割れます。
- 記録:同じ人の走行が、2つのアカウントに分かれて保存される
- 統計:月の合計が、アカウントごとにばらばらになる
- ランキング:同じ人が別人として集計され得る
Firebase には、複数のログイン方法を1つのアカウントに連携する仕組みがあります。アカウント連携のドキュメントによると、連携すれば同じ Firebase のユーザーIDでログインできるようになります。ただし、連携しようとする資格情報がすでに別のアカウントに紐づいている場合は連携に失敗し、2つのアカウントのデータをどうまとめるかはアプリ側で扱う必要があるとされています。今回のように両方のアカウントにすでに記録がある状態は、このケースに当たります。
このアプリでは、アカウントの連携も「別のログイン方法で入っています」といった案内も実装しておらず、対応するかどうかも判断していません。
数字の食い違いを不具合と決める前のチェックリスト
次に同じことが起きたときのために、調べる順番をまとめます。
- アカウント:2つの画面は同じアカウントでログインした状態で見たものか。画面からそれを確かめる手段はあるか
- 端末:同じ端末で見たものか。別の端末なら、それぞれどのアカウントで入っているか
- 撮影時刻:2枚のあいだに、記録や同期など、データが変わり得る操作をしていないか
- データ範囲:期間・完了済みかどうか・丸め方など、集計の条件が同じか
- 合計の分解:合計を日付や記録ごとに分け、足し直してそれぞれの画面と一致するか。一致しない項目はどれか
今回は、コードに差がないと分かった時点で入力のデータを疑うべきでした。8分で保存値が変わったという仮説は、見た目の数字の動きに引っ張られたものです。
コードが同じなら、違うのはデータです。集計の不具合を探す前に、その数字が誰のデータから出ているかを確かめる。今回の調査で残った順番は、それだけです。