코드 개선 TIL

leejihyeon·2026년 5월 10일

1. Dto에 Lombok도입

1. [문제 인식 및 정의]

client패키지에 WeatherDto의 가독성과 유지보수을 위해 생성자를 지우고 어노테이션 추가

2. [해결 방안]

2-1. [의사결정 과정]

단순 생성자 반복을 줄이기 위해 두 가지 방법을 고민했습니다.

방법 1. Record 도입

  • 생성자, Getter 생성

방법 2. @RequiredArgsConstructor 활용

  • 기존 Lombok라이브러리를 활용해 어토네이션 한 줄로 간단히 해결

    → 제가 익숙한 방법을 활용하는 편이 좋을 것 같아 방법 2. 를 선택했습니다.

2-2. [해결 과정]

final키워드가 붙은 필드를 모아 생성자를 자동으로 생성해주는 어노테이션 @RequiredArgsConstructor을 적용하여 기존에 있던 생성자 코드를 대체했습니다.

개선 전 코드

@Getter
public class WeatherDto {

    private final String date;
    private final String weather;

    public WeatherDto(String date, String weather) {
        this.date = date;
        this.weather = weather;
    }
}

개선 후 코드

@Getter
@RequiredArgsConstructor
public class WeatherDto {

    private final String date;
    private final String weather;
    
}

3. [해결 완료]

3-1. [회고]

불변으로 다루는 필드는 @RequiredArgsConstructor@Getter 조합으로 우선시 하고 나중에 좀 더 Record에 대해 공부해서 Record방법을 사용하는 방식으로 하고자 합니다.

3-2. [전후 데이터 비교]

단순히 코드가 줄어든 것이 아니라 가독성이 좋아졌고 유지보수가 크게 개선되었습니다.

전 코드에서는 필드가 늘어나면 그때마다 생성자 파라미터와 초기화 코드를 일일이 수정해야 하는 번거로움이 있었습니다. 이는 개발자의 실수로 이어질 가능성이 있고 가독성이 줄어듭니다.

코드를 바꾼 후 자동으로 생성자를 주입해주니 개발자의 실수도 줄어들고 가독성과 유지보수가 좋아졌습니다.

→ 불변 필드가 있는 요청 DTO에 생성자 삭제 후 어노테이션 추가

2. 로그인 에외 통일

1. [문제 인식 및 정의]

로그인(signin)로직을 검토하던 중, 인증 실패 상황에서 다른 타입의 예외가 발생하는 것을 발견했습니다.

  • 예외 타입 불일치 : 존재하지 않는 이메일로 로그인 시도 시 InvalidRequestException 발생
    • 비번 불일치 시 : AuthException 발생
  • 이메일이 존재하지 않을 때 단순히 클라이언트의 형식 오류(400 BAD Requeset)로 처리됩니다.

2. [해결 방안]

2-1. [의사 결정 과정]

로그인 과정에서 발생하는 인증 실패 예외들을 로그인 실패라는 비즈니스에 맞춰 일관되게 AuthException(401 Unauthorized)로 예외처리를 했습니다.

2-2. [해결 과정]

가입되지 않은 유저를 조회할 때 던지는 예외를 InvalidRequestExcption에서 AuthException으로 변경했습니다.


개선 전 코드
@Transactional(readOnly = true)
public SigninResponse signin(SigninRequest signinRequest) {

    User user = userRepository.findByEmail(signinRequest.getEmail()).orElseThrow(
            () -> new InvalidRequestException("가입되지 않은 유저입니다."));

    if (!passwordEncoder.matches(signinRequest.getPassword(), user.getPassword())) {
        throw new AuthException("잘못된 비밀번호입니다.");
    }

    String bearerToken = jwtUtil.createToken(user.getId(), user.getEmail(), user.getUserRole());

    return new SigninResponse(bearerToken);
}

개선 후 코드

@Transactional(readOnly = true)
public SigninResponse signin(SigninRequest signinRequest) {

    User user = userRepository.findByEmail(signinRequest.getEmail()).orElseThrow(
            () -> new AuthException("가입되지 않은 유저입니다."));

    if (!passwordEncoder.matches(signinRequest.getPassword(), user.getPassword())) {
        throw new AuthException("잘못된 비밀번호입니다.");
    }

    String bearerToken = jwtUtil.createToken(user.getId(), user.getEmail(), user.getUserRole());

    return new SigninResponse(bearerToken);
}

3. [해결 완료]

3-1.[회고]

이 예외가 이 비즈니스 로직에 적절한 타입인가?를 고민했습니다. 나쁜 사용자가 예외를 보고 나쁜 짓을 안하게 에러 처리를 일관되게 설계하고 메시지를 "잘못된 비번입니다."라고 하기보다는 "이메일 혹은 비번이 일치하지 않습니다."와 같이 하는 쪽이 보안에 좋을 것 같다는 생각을 했습니다.

3-2. [전후 데이터 비교]

HTTP 상태 코드 401 Unauthorized로 일관 반환합니다.
전에는 이메일 오류 시 400 Bad Request / 비번 오류 시 401 Unauthorized 반환했습니다.

예외 핸들링을 InvalidRequestExceptionAuthException 두개를 해야 하나 싶었지만 수정 후 AuthException 이거 하나만 하면 됩니다.

또 같은 이유로 회원가입 시에도 InvalidRequestExceptionAuthException 로 수정

3. 리팩토링 for문을 Stream으로 수정

1. [문제 인식 및 정의]

getComments메서드에 for문을 Stream으로 수정하여 가독성을 높였습니다.

2. [해결 방안]

2-1. [의사결정 과정]

가독성이 좋게 Stream으로 선택하였습니다.

2-2. [해결 과정]

Stream의 maptoList()를 사용하였습니다.

개선 전 코드

@Transactional(readOnly = true)
public List<CommentResponse> getComments(long todoId) {
    List<Comment> commentList = commentRepository.findByTodoIdWithUser(todoId);

    List<CommentResponse> dtoList = new ArrayList<>();

    for (Comment comment : commentList) {
        User user = comment.getUser();
        CommentResponse dto = new CommentResponse(
                comment.getId(),
                comment.getContents(),
                new UserResponse(user.getId(), user.getEmail())
        );
        dtoList.add(dto);
    }
    
    return dtoList;
}

개선 후 코드

@Transactional(readOnly = true)
public List<CommentResponse> getComments(long todoId) {
    List<Comment> commentList = commentRepository.findByTodoIdWithUser(todoId);

    //  Stream API를 통한 직관적인 데이터 변환(Map) 및 불변 리스트 반환
    return commentList.stream().map(comment -> new CommentResponse(
            comment.getId(),
            comment.getContents(),
            new UserResponse(comment.getUser().getId(), comment.getUser().getEmail())
        ))
        .toList();
}

3. [해결 완료]

3-1. [회고]

스트림을 사용하므로써 코드 줄 수가 줄어들었다.

3-2. [전후 데이터 비교]

코드 라인 수 및 가독성이 좋아졌다.

0개의 댓글