Sale Commerce의 환불 상세 조회 API를 구현한 뒤 코드를 다시 살펴보다 한 가지 의문이 생겼다.
화면에는 일부 정보만 필요한데 굳이 Refund 엔티티 전체를 조회해야 할까?
기존 API는 정상적으로 동작하고 있었다.
기능적으로 버그가 있었던 것도 아니다.
하지만 읽기 전용 API의 목적에 비해 불필요한 데이터를 조회하고 있었다.
이번 글에서는 엔티티 전체 조회 방식에서 실제 응답에 필요한 데이터만 DTO로 직접 조회하도록 리팩토링한 과정을 정리한다.
기존 환불 상세 조회 흐름은 다음과 같았다.
Controller
↓
Query Service
↓
Refund Entity 전체 조회
↓
영속성 컨텍스트 관리
↓
DTO 변환
↓
Response
Repository에서 환불 ID와 회원 ID를 조건으로 Refund Entity를 조회한 뒤 Service에서 응답 DTO로 변환했다.
일반적인 JPA 조회 방식이고 기능 자체에는 문제가 없었다.
하지만 실제 API 응답을 다시 살펴보니 필요한 값은 일부뿐이었다.
환불 ID
주문 ID
결제 ID
환불 금액
환불 상태
환불 요청 시각
환불 완료 시각
실제 응답에 필요한 값은 총 7개였다.
해당 API는 환불 데이터를 변경하지 않는다.
사용자가 자신의 환불 상세 정보를 확인하기 위한 읽기 전용 API다.
Entity를 조회하면 JPA는 해당 객체를 영속성 컨텍스트에서 관리한다.
이는 데이터를 변경해야 하는 로직에서는 매우 유용하다.
하지만 이번 API에서는
Entity 조회
↓
아무런 상태 변경 없음
↓
DTO로 변환
↓
응답
만 수행하고 있었다.
Entity 자체가 가지고 있는 변경 기능이나 도메인 로직이 필요하지 않았다.
그래서 한 가지 기준을 세웠다.
데이터 변경이 필요한 기능
→ Entity 조회
화면에 보여주기만 하는 조회
→ 필요한 데이터만 직접 조회
조회 전용 객체를 별도로 만들고 Repository에서 실제 응답에 필요한 값만 직접 조회하도록 변경했다.
기존 구조는
DB
↓
Refund Entity 전체
↓
응답 DTO 변환
이었다.
변경 후에는
DB
↓
필요한 7개 컬럼 조회
↓
조회 DTO
형태가 됐다.
QueryDSL을 사용해 응답에 필요한 컬럼만 Projection했다.
이번 작업의 목적은 내부 조회 구조를 개선하는 것이었다.
따라서 프론트엔드나 API 사용자에게까지 변경을 요구하면 불필요한 영향 범위가 커진다.
기존 API 주소인
GET /refunds/{refundId}
를 그대로 유지했다.
응답 형식 역시 동일하게 유지했다.
즉
외부 API 계약
→ 그대로 유지
내부 조회 방식
→ Entity 전체 조회에서 DTO 직접 조회로 변경
한 것이다.
내부 구현을 변경했다고 해서 기존 기능의 결과까지 달라지면 안 된다.
그래서 조회 Service 테스트에서 응답 필드들을 다시 검증했다.
refundId
orderId
paymentId
refundAmount
status
requestedAt
completedAt
기존 API와 동일한 데이터가 반환되는 것을 확인해 리팩토링 과정에서 발생할 수 있는 회귀를 방지했다.
기존에는 Refund Entity 전체를 조회한 뒤 DTO로 변환했다.
변경 후에는 DB에서 응답에 실제 필요한 7개 컬럼만 직접 조회하도록 만들었다.
이번 작업은
500ms → 50ms
처럼 눈에 띄는 성능 수치를 만든 최적화는 아니다.
그래서 측정하지 않은 성능 개선 수치를 억지로 만들지 않았다.
대신
읽기 전용 API에서 필요하지 않은 Entity 전체를 조회할 필요가 있는가?
라는 관점에서 조회 구조를 다시 생각했고, API의 목적에 맞게 필요한 데이터만 가져오도록 개선했다.
JPA를 사용한다고 해서 모든 조회를 반드시 Entity로 해야 하는 것은 아니다.
Entity는 단순히 DB의 데이터를 담는 객체가 아니라 도메인 상태와 행동을 관리하는 역할을 가진다.
반대로 화면에 데이터를 보여주는 것만이 목적인 조회 API에서는 Entity 전체가 필요하지 않을 수도 있다.
이번 작업을 통해 앞으로 조회 API를 구현할 때
"이 기능에서 정말 Entity가 필요한가?"
를 먼저 생각해볼 수 있게 됐다.
데이터 변경이 필요한 기능과 단순 조회 기능의 목적을 구분하고, 상황에 맞는 조회 방식을 선택하는 것이 중요하다는 것을 배웠다.
..점점 블로그가 회색빛이 돌기 시작하네요..