かすてらすねお。

見聞録的ななにか。

『Clean Code』(2017)の第7章「エラー処理」を読んだ

第7章 エラー処理

書き手

  • エラー処理について語れるほどエラー処理を書いたことがない
  • 業務ではエラー処理を含むコードを読んだり修正したことがあるが、今でも何がその正解だったのかを理解できていない
  • エラー処理という文法は知っている(try-catch-finally-throw など)
  • Log.Error()みたいなのは書いてるくらい
  • この章はエラー処理のコーディングに関する理解の助けになるだろうか?

サマリ

  • (pp.150-151)
    • リターンコードを使用すると、ビジネスロジックとエラー処理が混在してしまう(リスト 7-1)
    • 例外を使用すると、2つの関心事を分離できる(リスト 7-2)
  • (pp.151-153)

    • 最初に try-catch-finally 文を書き、例外を強制的に送出するテストを書いて、テストが成功するように振る舞いを追加する
    • 責任範囲(スコープ)が明確になり、何(例外発生)が起きても一貫性を保つべき処理の単位(トランザクション)として設計できる
  • (pp.153-154)

    • Java にはチェック例外があるが、チェック例外のない言語でも堅牢なプログラムは書ける
    • チェック例外の代償はカプセル化を破壊し、開放/閉鎖原則に違反すること
    • 一般的なアプリケーション開発においては、代償が利益を上回る
  • 知らなかった・忘れた言葉

    • チェック例外
      • コンパイラによってチェックされる例外」のこと。コンパイラが「ここでエラーが起きる可能性があるから、必ず try-catch で囲みなさい」と強制してくる仕組み。
    • メソッドのシグネチャ
      • 「メソッドの名前、引数の型、戻り値の型」を含む、メソッドの定義情報のこと。最新の Java では、メソッドのシグネチャには例外の型も含まれる。
    • 開放/閉鎖原則
      • 「ソフトウェアの構成要素は拡張に対して開かれていて、修正に対して閉じていなければならない」という原則。
  • Java における非チェック例外の使用方法は?(AI に聞いた)

    • RuntimeException を継承したクラスを作成すればいいらしい。本当か知らんけど
// チェック例外の例
public class CustomCheckedException extends Exception {
    public CustomCheckedException(String message) {
        super(message);
    }
}

// 非チェック例外の例
public class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException(String message) {
        super(message);
    }
}
  • (pp.154)

    • 十分な情報を持ったエラーメッセージを作成して例外に含める
  • (pp.154-156)

    • 呼び出し元が必要とする例外クラスを定義する
      • サードパーティライブラリの複雑な例外を抽象化できる
      • 具体的なエラー情報を保持したままエラー処理をシンプルに書ける
  • (pp.156-157)

    • 「正常ケースのフローを定義する」とは?
      • 例外として扱っていた処理をスペシャルケースパターンで実装する
      • 例外を使わずにメインロジックをシンプルに保つ
  • (pp.158-159)

    • null を返さない
      • 多くの場合、null の代わりにスペシャルケースオブジェクトを返すとよい
      • NullPointerException が送出される可能性を最小限にする
  • (pp.159-160)

    • null を渡さない
      • 多くの言語では、呼び出し元から null を渡された時に対処する方法がない
      • null を渡すことを原則禁止とし、何かの間違いであることを明確にする

考察と要約

クリーンコード実現におけるエラー処理とは、「プログラムの状態が一貫性を失う可能性のある状況」への対処である。

  1. なぜ try-catch-finally を先に書くのか?
    • エラーとは「プログラムの状態の一貫性が破綻する可能性」
    • try-catch-finally を先に書き、「一貫性を保つべき範囲」を定義する
  2. なぜエラーを抽象化するのか?
    • 「状態の変化を適切なレベルで表現する」ための手段
    • 呼び出し元の都合に合わせる
  3. なぜすべてをエラーとして扱うべきでないのか?
    • 対処しきれないし、コードが読みにくくなるから
    • エラー = 異常という思い込みを解く(cf. スペシャルケースパターン、null 返却の回避)

感想

  • 例外を投げてくるライブラリを使う時に対処を考えられそうな気がしてきた

Follow me on X: @suneo3476Web