[TIL] 지저분한 Service 코드, 정적 팩토리 메서드로 깔끔하게 정리하기

2025. 12. 30. 17:12·Archive/TIL

1. "분리해도 괜찮은 부분"의 정체

오늘 수업 중 **로그인 로직(AuthService)**에서 '이 부분은 분리해도 돼요'라고 했던 부분은 바로 응답 객체(DTO)를 생성하는 과정이었다.

1.분리 대상 코드 (Before)

현재 AuthService는 로그인 검증뿐만 아니라, 응답 객체(DTO)를 하나하나 조립하는 일까지 하고 있습니다.

Java
// [AuthService.java]
// 서비스가 DTO의 필드 구조를 속속들이 알고 직접 조립함 (좋지 않음)
return AuthDto.LoginResponse.builder()
        .userId(userId)
        .userName(member.getUserName())
        .role(role)
        .token(token)
        .build();
  • 문제점:
    1. 서비스 코드가 길어지고 지저분해집니다.
    2. 나중에 DTO 필드가 바뀌면 서비스 코드도 수정해야 합니다. (낮은 응집도)

2. 분리 후 코드 (After)

이 builder 코드를 DTO 클래스 내부로 옮겨서, 정적 팩토리 메서드(Static Factory Method) 패턴으로 만듭니다.

(1) DTO 클래스 수정 (AuthDto.java)

"나(DTO)를 만드는 방법은 내가 제일 잘 알아"라며 생성 로직을 가져옵니다.

Java
// [AuthDto.java] 내부
@Getter
@Builder
public static class LoginResponse {
    private String userId;
    private String userName;
    private String role;
    private String token;

    // ★ 여기에 'of' 메서드 생성 (이게 바로 분리된 로직!)
    public static LoginResponse of(Member member, String token) {
        return LoginResponse.builder()
                .userId(member.getUserId())
                .userName(member.getUserName())
                .role(member.getRole().name())
                .token(token)
                .build();
    }
}

(2) 서비스 클래스 수정 (AuthService.java)

서비스는 이제 "재료 줄 테니까 만들어와"라고 명령만 내립니다.

Java
// [AuthService.java]
// 훨씬 깔끔해진 서비스 코드
return AuthDto.LoginResponse.of(member, token);

3. 왜 이렇게 분리하나요? (핵심 이유)

  1. 캡슐화(Encapsulation):
    • 어떤 필드에 어떤 데이터를 넣을지는 DTO 내부 사정입니다. 서비스가 알 필요 없게 숨기는 것입니다.
  2. 응집도 향상:
    • DTO와 관련된 코드는 DTO 파일에 모아두는 것이 관리하기 편합니다.
  3. 실수 방지:
    • 서비스마다 똑같은 builder 코드를 반복해서 쓰다 보면 오타나 누락이 생길 수 있는데, of 메서드 하나만 호출하면 되므로 실수가 줄어듭니다.

한 줄 요약:

"서비스단에 있는 지저분한 builder()...build() 코드를 DTO 내부의 of() 메서드로 캡슐화하여, 코드를 깔끔하게 만들고 유지보수성을 높이는 리팩토링입니다."

2. validateToken 메서드의 동작 원리

JWT 토큰이 유효한지 검사하는 validateToken 메서드는 단순히 "토큰이 있나?"만 보는 게 아니라, 위조 여부와 유효 기간을 동시에 체크하는 문지기 역할을 한다.

Java
public Optional<Claims> validateToken(String token) {
    try {
        Claims claims = Jwts.parser()
                .verifyWith(secretKey)      // 1. 서명(Signature) 검증
                .build()
                .parseSignedClaims(token)   // 2. 파싱 및 만료 시간(exp) 검사
                .getPayload();
        return Optional.of(claims);
    } catch (Exception e) {
        return Optional.empty();            // 3. 문제 발생 시 빈 값 반환
    }
}

✅ 핵심 검증 포인트

  1. 위조 검사 (verifyWith):
    • 서버가 가진 secretKey로 풀리지 않으면, 해커가 조작한 토큰으로 간주하고 즉시 에러를 뱉는다.
  2. 만료 검사 (parseSignedClaims):
    • 토큰 내부의 exp(만료시간)을 확인한다. 단 1초라도 지났으면 ExpiredJwtException을 발생시킨다.

📝 배운 점

  • try-catch를 사용한 이유는 라이브러리가 검증 실패 시 boolean을 리턴하는 게 아니라 **예외(Exception)**를 던지기 때문이다. 이를 안전하게 처리하기 위해 Optional로 감싸서 반환하도록 설계되었다.

'Archive > TIL' 카테고리의 다른 글

[TIL] 웹 데이터의 변신과 여행: 직렬화부터 JWT 저장까지  (0) 2025.12.29
[TIL] JPA 영속성 전이와 고아 객체: Cascade vs OrphanRemoval 정리  (0) 2025.12.16
[TIL] REST API 인증과 상태 관리: Session vs Token 정리  (0) 2025.12.09
[TIL] 리액트 핵심 이론 정리: 제이쿼리 차이, 클로저, 비동기  (0) 2025.12.05
[TIL] 리액트 라우팅과 전역 상태 관리: Router & Context API  (1) 2025.12.02
'Archive/TIL' 카테고리의 다른 글
  • [TIL] 웹 데이터의 변신과 여행: 직렬화부터 JWT 저장까지
  • [TIL] JPA 영속성 전이와 고아 객체: Cascade vs OrphanRemoval 정리
  • [TIL] REST API 인증과 상태 관리: Session vs Token 정리
  • [TIL] 리액트 핵심 이론 정리: 제이쿼리 차이, 클로저, 비동기
tlsgkstj
tlsgkstj
짱구의 성장 일기
  • tlsgkstj
    코딩하는 짱구
    tlsgkstj
  • 전체
    오늘
    어제
    • 분류 전체보기 (159)
      • About (1)
      • Projects (35)
        • Personal Projects (21)
        • Team Projects (14)
      • Engineering (20)
        • CS & Tools (0)
        • Backend Core (15)
        • Frontend (1)
        • Infra & Cloud (2)
        • AI & Tools (1)
      • Trouble Shooting & Issues (0)
      • Growth & Career (38)
        • Interview Prep (0)
        • Retrospectives (38)
      • Archive (65)
        • TIL (8)
        • Daily Dev Q&A (56)
  • 블로그 메뉴

    • 홈
    • About
    • Projects
    • Tech Stack
    • Dev Log
    • GitHub
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    java
    Project_Review
    til
    REACT
    커리어리셋
    Spring비교
    network
    경기기후바이브코딩
    OrphanRemova
    클로드코드
    backend
    aws_s3
    프로덕트개발자
    jpa
    데브페스트
    프로젝트회고
    SpringBoot
    devlog
    DevFestIncheon2025
    spring
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
tlsgkstj
[TIL] 지저분한 Service 코드, 정적 팩토리 메서드로 깔끔하게 정리하기
상단으로

티스토리툴바