728x90
도입
유저 회원가입 기능을 도입하면서, 흔히 간과되는 입력값 유효성 검증을 시스템적으로 구조화할 필요성을 느꼈다.
예를 들어 이메일 형식이 유효한지, 비밀번호가 보안 정책에 맞는지를 단순 if-else 로직으로 처리하기 시작하면, 곧 유지보수 지옥이 열리기 때문이다.
이번 포스트에서는 다음 내용을 중심으로 회원가입과 유효성 검증을 어떻게 모듈화했는지를 공유한다.
설계 목표
- 확장 가능하고 테스트 가능한 유효성 검증 구조
- 비즈니스 로직과 검증 로직의 명확한 분리
- 검증 실패 시 도메인 특화 예외 처리
- DDD 기반 도메인 모델 구성 (User, Provider 등)
설계 고려사항
항목 고려 내용
| 입력 검증 | 이메일/비밀번호 형식 규칙을 Validator로 위임 |
|---|---|
| 중복 체크 | 이메일 중복은 DB에 위임하고 예외로 처리 |
| 예외 설계 | CustomErrorCode 기반으로 HTTP 상태값 매핑 |
| 책임 분리 | 검증은 ValidatorFactory, 비즈니스는 AuthService |
구현 설명
1. ValidatorType 기반으로 검증기 식별
Validator<String> emailValidator = validatorFactory.getValidator(ValidatorType.EMAIL);
if (!emailValidator.validate(req.getEmail())) {
throw new AuthException(AuthErrorCode.INVALID_EMAIL);
}2. 비밀번호도 동일하게 처리
Validator<String> passwordValidator = validatorFactory.getValidator(ValidatorType.PASSWORD);
if (!passwordValidator.validate(req.getPassword())) {
throw new AuthException(AuthErrorCode.INVALID_PASSWORD);
}3. 유저 저장 처리
User user = User.builder()
.id(snowflake.nextId())
.email(req.getEmail())
.password(req.getPassword())
.provider(ProviderList.SYSTEM)
.createdAt(LocalDateTime.now())
.isEmailVerified(false)
.isDeleted(false)
.build();
userRepository.save(user);
검증기에서 검증이 실패하면 바로 Exception을 던지며 흐름을 끊는다.
회고 및 확장 가능성
회고
- 검증기를 enum 기반으로 등록해두니 기억 의존도가 낮아졌고,
- 테스트가 독립적이라서 단위 테스트 작성도 편리했다.
- 다만, 현재는 검증기 로직이 동기적으로 동작하기 때문에 성능 문제는 없다.
나중에 외부 API를 통한 유효성 체크(예: 이메일 실존 확인)가 들어오면 비동기 설계로 바꿔야 할 수 있다. - 엔티티 설계는 다음 글에 작성 하도록 하겠다
확장 아이디어
- 이메일 인증 로직 추가 시, 현재 구조 그대로 EmailVerificationService로 확장 가능.
- ValidatorFactory도 Map<ValidatorType, Validator<?>> 대신 스프링 빈 주입으로 변경해 유연하게 개선 가능.
- SignUpRequest의 필드가 늘어나도 서비스 로직은 깔끔하게 유지됨.
728x90
'BindProject' 카테고리의 다른 글
| [Backend] Auth모듈 : 역할(Role) 부여 기능 구현기 (0) | 2025.06.19 |
|---|---|
| [Backend] Auth모듈 :사용자 등록 로직의 책임 분리와 유효성 검사 개선 (2) | 2025.06.18 |
| [Backend] Auth모듈 : Validator 만들기 (0) | 2025.06.18 |
| [기획] BFF에서의 필터링 전략과 정합성 보장 설계의 관해 (2) | 2025.06.18 |
| [Backend] JWT 토큰 모듈 설계 및 구현기 (1) | 2025.06.17 |