例外処理はライブラリを置き換えたときに気付けない
rood_niさんのスプリント報 (12/3〜12/15)を読んで、ライブラリ移行時という観点が面白かったので記録しておこうと思った。このエントリを引用する。
- try で大きな範囲を囲うと try が何のためにあるのか読みにくい
- 例の catch はHTTP通信失敗とJSONパース失敗の両方を捕捉する可能性がある
- catch する例外クラスを限定するのはメリットよりデメリットが大きいかも
- 例は IOException のみを catch するが、後のPRでHTTP通信を scalaj.http から sttp に変更したことで機能しなくなった
- catch の網羅性は型によって保証されない
- HTTP通信失敗とJSONパース失敗は両方とも IOException だから、この例では例外クラスの限定は try の意図の説明になっていない
元のコードから重要な部分だけ抽出すると以下のような実装だった。
try { val res = scalaj.http.Http(uri.toString()).asString val data = Json.parse(res.body) res.code match { case 200 => Right(Json.fromJson[DtoMetrics](data).get) case _ => Left(UnexpectedError("unexpected error")) }} catch { case err: IOException => { Left(UnexpectedError(err.getMessage)) }}検査例外は別かもしれないが、確かにここでライブラリが投げる例外を catch できなくてもコンパイルエラーにはならないので気付けないこともあるだろう。これは面白い観点で、例外の問題をよく表現していると思った。
まあGoでも、エラーをセンチネルエラーとして扱ってしまうと、そういうことは起こりうる。