クリーンアーキテクチャに応用する「早期リターン+例外処理+レイヤード設計」
ここまでで「早期リターン」「例外処理」「サービス層とコントローラ層の分離」を見てきました。これをさらに発展させると、クリーンアーキテクチャの考え方に近づきます。
クリーンアーキテクチャの基本
- エンティティ層 → ビジネスルールの中心(ドメインモデル)
- ユースケース層 → アプリケーション固有のロジック(サービス層に近い)
- インターフェース層 → コントローラやAPI、UIなど外部との接点
- インフラ層 → DBや外部APIなど技術的な依存部分
👉 ポイントは「依存方向が内側に向かう」こと。ビジネスロジックは外部技術に依存しない。
サンプル構成(ユーザープロフィール取得)
エンティティ層(ドメインモデル)
public class UserProfile {
private String userId;
private String name;
private String email;
// getter/setterなど
}
Javaユースケース層(業務ロジック)
public class GetUserProfileUseCase {
private final UserRepository repository;
public GetUserProfileUseCase(UserRepository repository) {
this.repository = repository;
}
public UserProfile execute(String userId) throws UserNotFoundException {
UserProfile profile = repository.findById(userId);
if (profile == null) {
throw new UserNotFoundException("ユーザーが見つかりません");
}
return profile;
}
}
Java👉 早期リターンではなく例外を投げることで、ユースケース層は「異常系を外に伝える」役割に徹する。
インターフェース層(コントローラ)
public class UserController {
private final GetUserProfileUseCase useCase;
public UserController(GetUserProfileUseCase useCase) {
this.useCase = useCase;
}
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 = useCase.execute(req.getUserId());
return successResponse(200, "成功", profile);
} catch (UserNotFoundException e) {
return errorResponse(404, 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 UserRepositoryImpl implements UserRepository {
private final ExternalApi api;
public UserRepositoryImpl(ExternalApi api) {
this.api = api;
}
@Override
public UserProfile findById(String userId) throws IOException {
return api.fetchProfile(userId);
}
}
Javaポイントまとめ
- 早期リターン: コントローラ層で入力チェックを即終了。
- 例外処理: ユースケース層やインフラ層で「異常を外に伝える」役割。
- 責務分離:
- コントローラ → 入力チェック+レスポンス生成
- ユースケース → ビジネスロジック
- リポジトリ → データ取得(外部依存)
- テスト容易性:
- ユースケース層はモックリポジトリでユニットテスト可能
- コントローラ層は統合テストでレスポンス確認可能
✅ こうして「早期リターン+例外処理+レイヤード設計」を組み合わせると、クリーンアーキテクチャの思想に沿った 読みやすく・安全で・テストしやすい設計 が実現できます。
