Java | 早期リターン(ガード節)のメリットと注意点

Java Java
スポンサーリンク

早期リターン+例外処理+共通レスポンスを活かしたアーキテクチャ設計ベストプラクティス

ここまでのサンプルをさらに発展させて、サービス層とコントローラ層を分離した設計を紹介します。これは実務でよく使われる「レイヤードアーキテクチャ」の考え方です。


なぜ分離するのか?

  • コントローラ層 → 入力チェック、レスポンス生成、例外ハンドリング
  • サービス層 → 業務ロジック(ビジネスルール)の実装
  • メリット
    • コードの責務が明確になる
    • テストがしやすい(サービス層だけをユニットテスト可能)
    • 保守性が高まる(UIやAPI仕様が変わってもサービス層は再利用できる)

サンプル構成

コントローラ層(入力チェック+レスポンス)

public class UserController {
    private final UserService userService;

    public UserController(UserService service) {
        this.userService = service;
    }

    public Response getUserProfile(Request req) {
        // --- 早期リターンで入力チェック ---
        if (req == null) return errorResponse(400, "リクエストが空です");
        if (req.getUserId() == null || req.getUserId().isEmpty()) {
            return errorResponse(400, "ユーザーIDが必要です");
        }

        // --- サービス層呼び出し+例外処理 ---
        try {
            UserProfile profile = userService.fetchProfile(req.getUserId());
            if (profile == null) {
                return errorResponse(404, "ユーザーが見つかりません");
            }
            return successResponse(200, "成功", profile);

        } catch (IOException e) {
            return errorResponse(503, "外部サービスエラー: " + e.getMessage());
        } catch (Exception e) {
            return errorResponse(500, "予期せぬエラー: " + e.getMessage());
        }
    }

    private Response errorResponse(int code, String message) {
        return new Response(code, message);
    }

    private Response successResponse(int code, String message, Object data) {
        return new Response(code, message, data);
    }
}
Java

サービス層(業務ロジック)

public class UserService {
    private final ExternalApi api;

    public UserService(ExternalApi api) {
        this.api = api;
    }

    public UserProfile fetchProfile(String userId) throws IOException {
        // 業務ロジック:外部APIからプロフィール取得
        return api.fetchProfile(userId);
    }
}
Java

テスト設計の観点

  • サービス層テスト
    • fetchProfile("validId") → 正常なプロフィールを返す
    • APIモックで IOException を投げる → 例外が伝播する
  • コントローラ層テスト
    • req = null → 400エラー
    • userId = "" → 400エラー
    • サービス層が null を返す → 404エラー
    • サービス層が例外を投げる → 503 or 500エラー

👉 責務が分離されているので、サービス層はユニットテスト、コントローラ層は統合テストと役割を分けられる。


まとめ

  • 早期リターン: コントローラ層で入力チェックを即終了。
  • 例外処理: コントローラ層で外部要因を安全にキャッチ。
  • サービス層: 業務ロジックを担当し、テストや再利用が容易。
  • 共通レスポンス: エラーメッセージや成功レスポンスを統一して保守性アップ。

✅ この設計は「読みやすく・安全で・テストしやすい」コードを実現するためのベストプラクティスです。

Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました