Spring 개발일지

[대규모 AI 시스템 프로젝트] 추가 리팩토링 상황

김둘리 2026. 4. 9. 10:00

1-1. 페이징 공통화

페이징 단위 제한 로직이 각 서비스에 중복으로 존재했다. common 모듈로 이동해서 공통으로 관리한다.

// common/dto/PageableRequest.java
@Getter
public class PageableRequest {
    private int page;
    private int size;
    private String sortBy;
    private String direction;

    public PageableRequest(int page, int size, String sortBy, String direction) {
        this.page = page;
        this.size = List.of(10, 30, 50).contains(size) ? size : 10;
        this.sortBy = sortBy;
        this.direction = direction;
    }
}

 

1-2. APIResponse 개선

에러 응답 시 success: true가 반환되는 문제를 수정했다. ErrorResponse를 APIResponse로 통합하고 실패 응답 메서드를 추가했다.

// APIResponse.java
public static <T> APIResponse<T> fail(String message) {
    return APIResponse.<T>builder()
            .success(false)
            .data(null)
            .message(message)
            .build();
}

 

수정 전:

{
    "success": false,
    "status": 400,
    "errorCode": "VALIDATION_ERROR",
    "message": "공백일 수 없습니다"
}

 

수정 후:

{
    "success": false,
    "data": null,
    "message": "공백일 수 없습니다"
}

 

2. HttpMessageNotReadableException 핸들러 개선

UUID 형식 오류와 enum 오류를 구분하여 명확한 에러 메시지를 반환하도록 수정했다.

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<APIResponse<?>> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
    String message = e.getMessage();
    String errorMessage = (message != null && message.contains("UUID"))
            ? "올바른 UUID 형식이 아닙니다."
            : "유효하지 않은 입력값입니다.";

    return ResponseEntity
            .status(HttpStatus.BAD_REQUEST)
            .body(APIResponse.fail(errorMessage));
}

 

느낀 점

  • 마이크로서비스에서 서비스 간 통신은 FeignClient를 활용하면 REST API 호출을 인터페이스처럼 간단하게 구현할 수 있다.
  • Command 패턴을 적용하면 서비스 메서드의 파라미터가 줄어들고 객체 생성 책임이 명확하게 분리된다.
  • 매직 상수는 반드시 상수로 중앙 관리해야 유지보수 시 일관성을 유지할 수 있다.
  • 공통 로직은 항상 common 모듈로 분리해서 중복을 방지해야 한다.
  • 응답 양식은 성공/실패 모두 일관된 형식을 유지해야 프론트엔드와 협업이 수월하다.