애플리케이션 계층별로 입력값 검증을 적절히 분리하고 중복을 최소화하면서도 신뢰성과 안정성을 확보하는 것은 시스템 설계에서 매우 중요한 문제이다. 아래는 검증 범위와 책임을 나눈 방식과 그에 따른 트레이드오프에 대한 설명이다.
입력값을 DTO로 받고, 서비스에서 다시 도메인 규칙을 검증하며, DB에서도 제약 조건을 거는 구조에서 중복 검증이 자주 발생하게 된다. 이러한 상황에서는 검증 책임을 명확히 나누지 않으면 불필요한 코드 중복과 예외 처리 복잡도가 증가하게 된다.
: 각 계층에서의 검증 책임을 명확히 하여 중복을 최소화한다.
- 컨트롤러에서는 형식 검증만 수행한다.(@Valid 활용), 중복 여부나 상태값 검증은 서비스 계층에서만 처리하도록 분리한다.
- ex) 이메일 형식 검증은 @Email로 컨트롤러에서 처리, 이메일 중복 여부는 서비스에서만 체크.
: 동일한 검증 로직이 여러 서비스에서 반복된다면, 이를 별도의 Validator 클래스나 컴포넌트로 분리한다. -> 코드 중복줄일 수 있음.
// ex) 닉네임 유효성 검사용 Validator 클래스
@Component
public class NicknameValidator {
private static final Pattern NICKNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9가-힣]{2,12}$");
public void validate(String nickname) {
if (nickname == null || !NICKNAME_PATTERN.matcher(nickname).matches()) {
throw new IllegalArgumentException("닉네임은 2~12자의 영문/숫자/한글만 허용됩니다.");
}
}
}
ex)
- UNIQUE 제약으로 중복 데이터 방지
- CHECK 제약으로 값 범위 강제
모든 계층에 위같은 검증을 넣으면 안정성은 올라가지만,그만큼 중복 코드가 많아지고 유지보수성이 떨어질 수 있다.
반대로, 검증을 한 곳에서만 처리하면 코드가 깔끔해지지만,
실수나 우회 루트를 통해 잘못된 데이터가 들어갈 가능성이 있다.