「初回の検索がいつも固まる」の真因 — 現在地の取得は、失敗すらしないことがある — 制作日誌 #19
ビジネス

「初回の検索がいつも固まる」の真因 — 現在地の取得は、失敗すらしないことがある — 制作日誌 #19

経路アプリで、初回の検索だけがいつまでも終わらない。エラーも出ない。原因は現在地の取得が成功も失敗もせず永遠に待ち続ける状態で、しかも自分は最初、無関係な自分の配信を疑って誤った報告をした。

KIYODO00
#個人開発#iOS#障害対応#設計ミス#制作日誌

経路アプリに「初回の検索だけ、いつも固まるか異常に遅い」という症状があった。2回目からは普通に動く。エラーの表示も出ない。ただ、ぐるぐる回り続ける。

症状の並べ方

原因を探す前に、症状を全部書き出した。

  • 初回だけ遅い。2回目以降は速い
  • エラーが出ない。文言すら出ない
  • 読み込み中の表示が消えない

このうち「エラーが出ない」が、いま思えば一番の手がかりだった。処理が失敗しているなら、何らかの文言が出るはずだ。何も出ないということは、失敗していないということになる。

サーバーに届いているかを先に見た

クライアント側を読み始める前に、サーバー側を確認した。ここは意識的にそうしている。

  • サーバーの利用記録を見る → 経路の計算が2日前から1件も増えていない
  • 実況ログを流して、その場で検索を叩いてみる → リクエストが1件も届かない

これでサーバーは無実だと確定した。原因は、クライアントが通信を始めるより手前にある。この一手で、探す範囲が一気に狭まった。

固まる系の不具合では、この切り分けが効く。「サーバーまで届いているか」を先に見ると、犯人の側が半分に絞れる。

真因:成功も失敗もしない

犯人は、現在地を取得する処理だった。

位置情報を取る関数は、屋内・機内モード・シミュレータなど、位置が定まらない状況で成功もせず失敗もせず、永遠に待ち続けることがある。既知の挙動だ。

これを素朴に待つコードを書くと、こうなる。

  • 成功しないので、次の処理へ進まない
  • 失敗もしないので、例外にならない
  • 例外にならないので、後片付けの処理も走らない
  • 結果、読み込み表示が消えず、エラーも出ず、永久に回り続ける

症状の3点が、これで全部説明できる。「初回だけ」も説明がつく。電源を入れてから最初の測位は時間がかかるが、2回目以降は端末が直前の位置を持っているので即座に返るからだ。

自分が最初にやった誤り

ここが今回いちばん残しておきたい部分だ。

症状の報告を受けたとき、私は直前に自分がアプリの中身を更新していた。だから「私の更新が原因の可能性が高い」と、最初にそう報告してしまった。

実際に該当箇所の変更履歴を調べると、その行を最後に触ったのは4日前の別の変更だった。私の更新は無関係だった。

時間的な近さは原因ではない。 直前に自分が触っていると、どうしてもそこを疑いたくなるし、疑うこと自体は悪くない。悪いのは、裏を取る前に原因として報告してしまうことだ。誤った原因を先に共有すると、その後の調査が全員そちらに引っ張られる。

直し方

  • 現在地の取得は、時間で打ち切る包みを必ず通すようにした(10秒で打ち切り、取れなければ「取れなかった」を返す)
  • 生の関数を直接呼ぶ場所を作らないというルールにして、既存の呼び出しを全部置き換えた。同じアプリ2本で合計7箇所あった
  • 権限の確認は呼び出し側に残した。「許可されていない」と「測位できなかった」は、出すべき文言が違う
  • 打ち切ったあと、黙って代用しない。直前の位置や直線距離で埋め合わせると、間違った数字を正しい顔で見せることになる。止めて理由を伝える

最後の点は判断が分かれるところだと思う。だが**「近い値を勝手に出す」ことの危険さ**は、経路アプリでは特に大きい。合っているように見えて実は違う、という状態が一番たちが悪い。

同じ罠は、座標から住所を引く処理にもあった。そちらも同じ包みを通してある。

同じ形の罠を洗い出す

今回の修正のあと、「外部に聞いて返事を待つ処理」を全部洗い出した。同じ形をしているなら、同じ罠があるからだ。

待つ相手返事が来ないことがあるか対応
現在地の取得ある(今回)10秒で打ち切り
座標から住所を引くある同じ包みを通した
自前サーバーへの通信ある通信の仕組みに打ち切りあり
ストアの購入処理ある画面側で操作を戻せるようにした
端末内の保存領域ほぼ無いそのまま

こうして並べると、「打ち切りが要る処理」と「要らない処理」の線引きがはっきりする。線引きは単純で、自分のアプリの外に聞きに行くかどうかだ。外に聞く処理は、返事が来ない可能性を必ず持っている。

逆に、この線を引いていない状態でコードを書くと、「たまたま返事が速い環境」でだけ動くアプリになる。開発中の自分の端末は、たいてい環境が良い。開発機で再現しない不具合の多くは、この線引きの漏れから来るというのが今回の結論だった。

学んだこと

  • 「エラーが出ない」は手がかり。 失敗していないなら、待っている
  • 固まったら、まずサーバー側の記録を見る。 届いていなければクライアント、届いていればサーバー。1回の確認で半分に絞れる
  • 時間で打ち切らない待ちを書かない。 外部(OS・通信・センサー)に聞く処理には、必ず打ち切りを付ける
  • 直前の自分の変更を疑うのはよいが、報告の前に変更履歴で裏を取る。 推測を原因として共有しない
  • 同じ罠は必ず複数箇所にある。 1箇所直したら、同じ呼び方をしている場所を全部洗う。今回は7箇所だった

Comments (0)

No comments yet. Be the first to leave one.