
通信エラーのクライアント側の扱いについて
-
2022年2月3日
こんにちは。ココネで『ポケコロ』のクライアント開発をしている五十嵐です。
今回はモバイルアプリサービスにおいて「クライアント側でリクエストした通信がエラーだった場合」にどう取り扱うべきか、について論じたいと思います。
はじめに
みなさんはモバイルアプリを使っている時に通信エラーが表示されたらどう思うでしょうか。
クライアント開発者:「おいおいサーバーしっかりしろよ」ととりあえず責任転嫁する
サーバー開発者:ドキッとしつつ「おいおいWiFiしっかりしろよ」と現実逃避する
一般ユーザー:「おいおい運営しっかりしろよ」と思いながら「○○使えない」「○○重い」とツイートする
結局のところ、通信エラー表示というのは見せてもマイナスの効果しかないと言えます。
ではなぜ見せるのか、それは見せないと別の問題があるからですね。
モバイルアプリサービスの特性上、できることなら見せたくない、だけど見せざるをえない、というジレンマがあるのが通信エラー表示とローディングです。
今回はその通信エラー表示について、どう取り扱うべきかを考えてみましょう。
なお、ここで扱う「通信エラー」はネットワーク接続状況に起因するものとしています。
サーバー処理で発生したエラーは原因特定が可能なため適切に例外処理を施しているという前提で考えています。
エラー1:クライアントからのリクエストがサーバーに届かなかった
エラー2:サーバーからのレスポンスがクライアントに届かなかった |
のいずれかのエラーが発生したものと思ってください。
「クライアントからリクエストを投げたものの、それを処理されたかどうかわからないことがわかった」状態です。
最適なエラー表示について考える
いくつか例をもとに考えてみましょう。
例1. 所持品リストのページングでエラーになった
例2. コーデを変更して保存したらエラーになった 例3. アイテムを購入したらエラーになった |
このそれぞれでどんなエラーを出してどう処理するのがいいでしょうか?
例1. 所持品リストのページングでエラーになった
所持品でなくてチャットのメッセージリストでも友達一覧でもいいですが、一度の通信で取得しきれない量のリストをスクロールして見せる(無限スクロール)ときの2ページ目以降の取得がエラーだった、と思ってもらえればいいと思います。
これを律儀に「通信エラーが発生」とかアラートを出すとどう見えるでしょうか。
無限スクロールタイプのUXは通信のトリガーをユーザーに気付かせないのがキモだと思います。次のページを先読みしてロードしておくことで、通信していると気付かないままスムーズに大量のリストをスクロールすることができます。なのに通信に失敗したらアラートが出てしまっては台無しですね。
この場合は通信エラーのアラートを出さないことが望ましいと言えます。
ただアラートを出さないだけだと次のページがロードできないだけですので、数回の自動リトライはしておくのがいいですね。
例2. コーデを変更して保存したらエラーになった
こちらは「状態を上書き変更するリクエスト」でエラーになったケースです。
この場合もリトライで良さそうですが、仮にサーバー側の処理が「同じコーデであれば変更がないのでエラーを返す」となっていたらどうでしょうか。
一度目の通信でサーバーに届くもののサーバーからのレスポンスがタイムアウト等により受け取れなかった場合、サーバー側ではすでに上書き変更が完了している状態です。
その状態で同じコーデでリトライ通信を行うと、今度は保存済みコーデと同じなので「変更なし」のアラートを表示することになってしまいます。
こういった通信の場合は、
- サーバー側で上書きする内容が同じであっても成功にする
または
- 上書きする内容が同じというエラーはクライアント側で無視して成功にする
という、リトライすることを前提にしたエラー表示が必要になってきます。
あくまでも変更した時だけ成功にしたいのであれば、クライアント側で変更したことを確認した上でサーバー側での変更確認を無視する、といった処理になるでしょうか。
例3. アイテムを購入したらエラーになった
処理を誤ると問題になりやすいのがこのケースです。
アイテム購入時に「通信エラーが発生」と出た場合、「買えた」とは思わず「買えなかった」と思いますよね。
買えなかった場合にどうするか、改めてもう一度買いますよね。
その結果、同じアイテムを意図せず複数購入してしまう、ということが起きてしまいます。
買えたかどうかわからない以上はリトライは不可、「買えたかもしれないから購入履歴を確認してね」というような案内を出すにとどめるのが無難でしょうか。
さて、三つの通信エラーの例を見てみましたがいかがでしょうか。
通信エラーの処理をどうするかは、サーバー側でどう処理されるか、さらに言うとDBがどう更新されるか、に依存してくるように思えます。
例1 単純なリストの表示だけなのでDB操作は検索のみで更新無し。 DB更新は0回 例2 データの上書きなのでDB更新あり。 ただし何度同じリクエストをしても更新状態は同じ。 DB更新回数は1回 例3 データ追加なのでDB更新あり、かつリクエストするたびにデータ状態が変わる。 DB更新回数はリクエストした回数 |
それぞれの対策で書き直すとこうなります
DB更新回数が0回の通信の場合:
自動リトライ可能 DB更新回数が1回の通信の場合: リトライ可能だが更新有無による考慮が必要 DB更新回数が2回以上の通信の場合: リトライ不可 適切にアラートを表示して案内する必要がある |
まとめ
まとめると
- データ取得のみの通信の場合はできるだけ通信エラーを表示させない工夫をする
- 同じパラメータで結果が変わらない通信の場合はリトライ後に成功させる
- 同じパラメータで結果が変わる通信の場合はわかりやすい案内をする
ということを通信ロジック追加の際に心掛けておくといいかと思います。
終わりに
通信エラー処理に関して論じてみましたがいかがでしたでしょうか。
これに関してはあまり仕様書に記載されることもないし、QAでテストケースを作られることも少ないように思います。
ただし考えずに作ってしまうと操作性が悪くなったりユーザーに誤解を与えてしまうこともあるため、問題を表面化させないという地味な「開発の腕の見せ所」ではないでしょうか。
クライアント開発者は元より、サーバー開発者も自分が作ったAPIが通信エラーになったときにリトライしてもいいかどうか、相談しながら作ってみることをお勧めします。
ココネでは一緒に働く仲間を募集中です。
ご興味のある方は、ぜひこちらの採用特設サイトをご覧ください。