[프로젝트 회고] 모두의 후기 검색과 마이페이지 응답 DTO 리팩토링

들어가며

모두의 후기 프로젝트에서 검색과 마이페이지 기능을 정리하며 응답 DTO 리팩토링을 진행했다.

처음에는 기능별로 응답 DTO를 만들다 보니 비슷한 데이터인데 이름과 구조가 조금씩 달라졌다.
검색 결과, 마이페이지 리뷰 목록, 북마크 목록은 모두 게시글 목록을 반환한다는 공통점이 있었다.

그래서 BoardSearchResponseSliceBoardResponse로 정리하고, 검색과 마이페이지 응답 구조를 맞추는 작업을 했다.

문제 상황

초기 구조에서는 API마다 응답 DTO가 따로 있었다.

물론 기능이 다르면 DTO가 다른 것은 자연스럽다.
하지만 실제 응답 내용을 보면 거의 같은 게시글 목록인데 이름만 다르거나 필드 구조가 조금씩 다른 경우가 있었다.

이런 상태가 계속되면 다음 문제가 생긴다.

  • 프론트엔드에서 API마다 응답 파싱 방식이 달라진다.
  • 백엔드에서 비슷한 DTO 변환 로직이 반복된다.
  • 필드 하나를 추가하거나 수정할 때 여러 DTO를 같이 봐야 한다.
  • API 응답의 일관성이 떨어진다.

그래서 목록 응답 구조를 정리할 필요가 있었다.

SliceBoardResponse로 통합

검색과 마이페이지에서 공통으로 사용할 수 있는 응답 DTO로 SliceBoardResponse를 사용했다.

이름에서도 의도를 드러내고 싶었다.

1
Slice 기반 게시글 목록 응답

검색 결과든, 내가 쓴 리뷰든, 내가 북마크한 리뷰든 결국 화면에서는 게시글 목록 형태로 보여준다.

따라서 공통 응답 구조를 만들고 각 Controller에서 이를 사용하도록 정리했다.

CustomPageResponse와 CustomSlicePageResponse

프로젝트에서는 페이지 응답을 통일하기 위해 CustomPageResponse, CustomSlicePageResponse 같은 구조를 사용했다.

일반 페이지네이션과 커서 기반 Slice 응답은 성격이 조금 다르다.

  • Page: 전체 개수, 전체 페이지 수가 필요할 때 적합
  • Slice: 다음 페이지 존재 여부 중심, 무한 스크롤에 적합

검색과 목록 조회에서는 Slice 기반 응답이 잘 맞았다.

전체 개수를 항상 계산하면 비용이 커질 수 있고, 사용자는 다음 데이터가 있는지만 알면 되는 경우가 많기 때문이다.

SearchService 정리

응답 DTO를 정리하면서 SearchService 내부 로직도 함께 다듬었다.

정렬 조건과 커서 기반 페이징 로직이 한눈에 보이도록 정리했고, Controller에서 사용하는 응답 타입도 맞췄다.

리팩토링을 하면서 느낀 점은 DTO 이름을 바꾸는 작업이 생각보다 넓은 영향을 가진다는 것이었다.

Controller, Service, 테스트, 프론트엔드 연동 흐름까지 확인해야 했다.
그래서 DTO 리팩토링은 작아 보여도 협업 중에는 공유가 꼭 필요하다.

성능보다 일관성

이번 작업은 성능 개선보다는 유지보수성과 응답 일관성에 가까웠다.

물론 불필요한 변환 로직이 줄어드는 효과는 있었지만, 핵심은 다음이었다.

1
비슷한 목록 API는 비슷한 응답 구조를 가진다.

이 원칙이 지켜지면 프론트엔드에서 API를 사용하는 경험이 좋아지고, 백엔드에서도 새로운 목록 API를 만들 때 기존 구조를 재사용할 수 있다.

배운 점

이번 리팩토링을 하면서 API 설계에서 “일관성”이 얼마나 중요한지 느꼈다.

기능 하나만 보면 DTO가 조금 달라도 큰 문제가 없어 보인다.
하지만 서비스가 커지고 API가 늘어나면 작은 차이가 계속 쌓인다.

그래서 초기에 응답 구조의 기준을 잡아두는 것이 중요하다.

마무리

검색과 마이페이지 응답 DTO 리팩토링은 화려한 기능 추가는 아니었다.

하지만 프로젝트를 오래 유지하려면 이런 정리 작업이 꼭 필요하다고 생각한다.

API는 프론트엔드와 백엔드가 함께 사용하는 약속이다.
그 약속이 일관적일수록 협업은 편해지고, 변경 비용은 줄어든다.

Leave a comment