書くワケ
途中からアサインしたプロジェクトでのタスクで、外部ライブラリを使用した通信のエラーハンドリングで躓いたのがきっかけ。
これからエラーハンドリングを実装する際に必ず思い出したいがために書きます。
エラーハンドリングとは
プログラムの実行中にエラーが発生した際に、すぐに実行を終了せず、あらかじめ用意しておいた処理を行うこと。
今回のエラーハンドリングの要件
ユーザーがこちらの意図しない特定の操作をした場合に、例外が発生し、通信が途切れ、それ以降は永久に繋がることはないのに何度も繋ぎ直そうとしてしまう。
↓
そのためその特定の操作が行われた際には、強制的に別の画面へ遷移させたい
1 何を防ぎたいのか?を明確にする
エラーハンドリングを実装する際には、必ず明確に「〜を防ぎたい」「〜が起こらないようにしたい」といった目的があるはずです。
しかし、ここが曖昧、または広義になってしまっている場合には注意が必要です。
今回のエラーハンドリングの要件の場合、下記の様に実装してしまうのは危険です。
// 省略
const connect = (): void => {
// 色々省略
//接続に成功していないのに通信しようとして例外が起きてるな...
//よしここに分岐入れて接続に成功していない場合は強制的に画面遷移させよう
if (connectId) {
//接続に成功した場合の処理
} else {
// 失敗した場合には画面遷移
window.location.href = '/home'
}
}
// 省略
上記は実際に僕がエラーハンドリングを実装する際にやってしまった手法です。
上記の防ぎ方の何が問題なのか?
先に申し上げておくと、問題ではないパターンもあるんです。
接続に成功している場合には、成功した処理、失敗した場合には、それに応じた処理を書くのは、おかしいことではないと言えます。
それを踏まえた上で、このエラーハンドリングが問題であると断定する前提条件は、上記コードの分岐がその特定の操作が行われた場合にのみfalse判定されるわけではないということです。
問題点その1 上記で挙げた特定の処理意外にもここに引っかかる可能性があることを考慮できていない
そもそもこのエラーハンドリング実装の理由は、ユーザーに特定の操作をされた際に発生する、再接続の無限ループが起こらない様にするという要件です。
しかしこれでは、通信が、他の理由で失敗した際にも、elseに入ってしまい、想定していた正常なリトライも行えなくなる可能性があります。
上記の分岐はユーザーに特定の操作をされた際にのみfalseになるわけではない判定だったのです。
問題点その1 エラーの拾い方が広義すぎる場合、他のエラーを握りつぶしてしまう
上記とほぼ似たような内容ですが、特定の処理の際にのみelseになるわけではないので、他のエラーを握りつぶしてしまう可能性があります。
本来はキャッチすべきエラーも握りつぶされてしまい、問題が起きた時も直すべきところに当たりをつけるのが困難になる可能性があります。
対策
防ぎたい事象の時のみ通る場所を作ってあげる
// 省略
const connect = (): void => {
// 条件を追加し、特定の事象は後続の処理へ行かない様に修正
if (!connectId && isUnableConnect) window.location.href = '/home'
//省略
}
// 省略
条件を追加し、ユーザーに特定の操作を行われた場合以外は、false判定されない様に修正しました。
2 外部ライブラリが絡むエラーハンドリングを実装する際には、無理矢理ロジックで解決しようとせず、ドキュメント等を読み特定のエラーをキャッチできるイベントがないかを探す
ライブラリ等を使用することにより、使い手は細かいことを気にすることなく、機能を「動かす」ことができます。
しかし、ライブラリを組み込んだ際のエラーハンドリングはきちんとできているのでしょうか?
僕が今回実感した外部ライブラリを使用する際のエラーハンドリングで一番大切なことは、公式ドキュメントを読むことです。
当たり前です。当たり前なのですが、初心者ほど、誰かが噛み砕いてくれた記事を一生懸命探してしまおうとしませんか?僕もその1人です。
ログを追い、「ここで処理が止まっている!」と該当箇所を見つけた興奮さながらに、そのままそこにロジックを足して、「よし!動いた!」と安堵するのは安直すぎます。
まず、理解していないライブラリであれば、公式ドキュメントを読みましょう。
今回僕がエラーハンドリングを施そうと考えた処理に関わっていたライブラリは、SkyWay JavaScript SDKというものです。
https://webrtc.ecl.ntt.com/api-reference/javascript.html#events
上記のリファレンスを参照したところ
・エラーが発生した際に発火するイベント
・エラーの判別方法
までしっかりと明記されています。
これのおかげで「この処理で〜なるということは、こう!」とはっきりと断言できる実装となりました。
最後に
エラーハンドリングはアプリケーションには確実に必要なものだが、実装の仕方を誤ると、エラーを握りつぶしてしまったり、機能追加の際に、余計な手間がかかったりしてしまいます。
エラーハンドリングを実装する際には、今自分がキャッチしたい特定のエラーのみを拾う様にする。
取りこぼしなく広義のエラーハンドリングを実装したい場合には、その意図をコメント等に残しておけば、次に見た人が「エラーを広く拾っているな」と直感的に理解することができるため、上記のデメリットを克服できると考えます。