
검증 로직은 Service 계층 내부에 위치시키되,
상태와 의존성이 없는 공통 검증은 유틸 클래스로 분리하여
재사용성과 테스트 용이성을 확보하는 것이 가장 이상적인 구조입니다.
넓은 의미에서는 비즈니스 로직에 포함됩니다.
다만, 그 성격에 따라 위치와 구현 방식이 달라져야 합니다.
1. 의미에 따른 구분
| 구분 | 예시 | 위치 |
|---|---|---|
| ✅ 비즈니스 로직 | “중복된 제목은 등록 불가” “마감 시간이 지난 게시글은 수정 불가” | Service, Domain 메서드 |
| ⚙️ 단순 유효성 검사 | “제목은 null이 아니어야 함” “제목은 30자 이하” | 유틸 클래스 또는 Validator |
2. 특징별 상세 비교
| 항목 | 비즈니스 로직 | 유효성 검증 (Validation) |
|---|---|---|
| 기준 | 도메인의 "규칙", 정책 | 형식, 범위, 기본 제약 |
| 위치 | Service / Domain Entity | 유틸 / Validator |
| 의존성 | DB 조회, 상태 판단 | 없음 (보통 값만 체크) |
| 변화 가능성 | 비즈니스 요구에 따라 바뀜 | 고정적, 반복적 패턴 |
예1. "제목은 30자 이하"
→ ⚙️ 단순 유효성 검증
→ 유틸 클래스에 둠 → PostValidator.validateTitleFormat()
예2. "이미 등록된 제목은 안 된다"
→ ✅ 비즈니스 로직
→ DB 조회 필요 → Service에서 처리
예3. "마감 시간이 지난 게시글은 수정 불가"
→ ✅ 도메인 정책
→ Domain 내부 메서드 → post.canUpdate() 등으로 구현
| 구분 | Service 내부 메서드 | 유틸 클래스 (정적 메서드) |
|---|---|---|
| 재사용성 | ❌ 클래스 내부에서만 가능 | ✅ 모든 계층에서 재사용 가능 |
| 테스트 용이성 | ❌ 의존성 주입 필요 | ✅ 단독 단위 테스트 가능 |
| 책임 분리 | ❌ 검증 책임이 서비스에 포함됨 | ✅ 서비스는 핵심 로직에 집중 가능 |
| 의존성 | 보통 Spring Bean 필요 | 없음 (static 메서드만 사용) |
Java에서 유틸리티 클래스는 상태를 가지지 않고,
정적(static) 메서드만 제공하는 클래스입니다.
public final class Utils {
private Utils() {} // 인스턴스화 방지
public static void doSomething() {
// ...
}
}