엔티티 DTO 변환 위치

2025. 1. 10. 16:38·Spring

이 글을 쓰게된 배경

프로젝트를 진행하다보니 문득 서비스 계층의 절반이 엔티티를 DTO로 변환하는 코드인 것이 보여서 이걸 이대로 두는 것이 맞는지 다른 사람들은 어떻게 하고 있는건지 더 좋은 방법은 없는건지 궁금해 져서 알아보는 겸 이 글을 작성했습니다.

 

컨트롤러 vs 서비스

인터넷 검색을 해본 결과 사람들은 주로 DTO 변환을 컨트롤러 계층 vs 서비스 계층 으로 두고 의견이 많이 갈렸습니다.

저는 컨트롤러 계층에서 DTO 변환을 한다는 건 생각도 못했기 때문에 신선했습니다.

DDD 4계층에 따르면 컨트롤러는 사용자에게 UI를 제공하는 역할이 컨트롤러의 역할입니다. DTO가 사용자에게 어떤 데이터를 보여줄 지 결정하는 것이기 때문에 위 원칙에 따르면 컨트롤러에 있는 것이 더 바람직해 보입니다. 서비스 계층은 비즈니스 로직을 처리하는 계층입니다. 

 

아래는 이 문제에 대한 김영한님의 의견입니다. 김영한님의 답변을 보면 결국 서비스 계층에서 변환하는지 컨트롤러 계층에서 변환하는지에 대한 답변은 나와있지 않지만 DTO의 위치에 대한 의견을 알 수 있습니다. 서비스계층에서 DTO를 변환한다면 서비스와 DTO를 같은 패키지에 두어야 한다는 것입니다. 그리고 의존관계를 굉장히 중요하게 여기시는 것 같았습니다. 다른 계층에서 엔티티 계층을 의존하는 것이 바람직하다고 하십니다. 개인적으로는 결국 어디에서 변환을 하든 의존관계를 최대한 줄이자는 결론이라고 해석했습니다.

https://www.inflearn.com/community/questions/139564/dto-%EC%82%AC%EC%9A%A9%EC%8B%9C%EA%B8%B0%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%88%EB%AC%B8

 

Dto 사용시기에 대한 질문 - 인프런 | 커뮤니티 질문&답변

누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요.

www.inflearn.com

 

다음은 이 문제에 대한 여러 사람의 의견입니다.

정말 놀랍게도 가장 많은 추천을 받은 댓글은 DTO 변환도 비즈니스 로직의 일부로 보고 서비스 계층에서 하는 것이고 두번째로 많은 추천을 받은 댓글은 컨트롤러에서 변환을 하는 것을 추천한다는 것입니다.

https://stackoverflow.com/questions/47822938/which-layer-should-be-used-for-conversion-to-dto-from-domain-object

 

Which layer should be used for conversion to DTO from Domain Object

We are creating rest api's with Spring Boot. We have three layers in our project(Repository, Service and Controller). Lets say I have GetUser api in my controller that return UserDTO object. @

stackoverflow.com

Mapper 클래스

이번에 새롭게 발견한 것이 있는데 바로 매퍼클래스 라는 것입니다. 매퍼클래스의 역할은 단순히 Entity를 DTO로 변환하거나 DTO를 Entity로 변환하는 코드를 모아놓은 클래스입니다. 

@Component
public class OrderItemMapper {

    public OrderItemDTO.Response orderItemToOrderItemResponse(OrderItem orderItem) {

        return OrderItemDTO.Response.builder()
                .orderItemKey(orderItem.getOrderItemKey())
                .amount(orderItem.getAmount())
                .itemTotalPrice(orderItem.getItemTotalPrice())
                .holeJson(orderItem.getHoleJson())
                .chamfer(orderItem.getChamfer())
                .price(orderItem.getPrice())
                .estName(orderItem.getEstName())
                .material(orderItem.getMaterial())
                .shipmentDate(orderItem.getShipmentDate())
                .surface(orderItem.getSurface())
                .method(orderItem.getMethod())
                .build();
    }
}

//사용
OrderItemDTO.Response orderItemResponse = orderItemMapper.orderItemToOrderItemResponse(orderItem);

 

위처럼 작성해주면 됩니다. 이렇게 작성하면 서비스 계층에서 길게 Entity를 DTO로 변환하는 과정이 보이지 않아 비즈니스 로직이 깔끔해지고 메소드명을 통해 어떤 무엇이 무엇으로 변환하는지 알 수 있기 때문에 가독성에서도 뛰어나다고 생각합니다. 다만, 단점으로는 변환과정을 서비스 계층에서 알 수 없기 때문에 의존관계가 하나 더 생기는 것으로도 볼 수 있습니다. 김영한님은 의존관계를 줄이라고 하셨지만.. 

서비스 계층의 반복적인 builder들을 보면 이상하게 좋지 않은 코드를 작성하고 있다는 느낌(압박)을 받습니다.

정리

관련 글을 정말 많이 읽었지만 결국 이 문제는 현재로써는 정답이 없다는 것을 알 수 있었습니다..
이런 문제를  취향 차이라고 하기가 좀 이상할 수도 있지만 결국 취향의 차이거나 프로젝트의 특성 or 비즈니스 적인 것에 의해서 결정하는 것이 가장 바람직해 보입니다. Mapper클래스는 개인적인 취향으로는 쓰고 싶은데 이게 좋은 방법인지에 대한 확신은 서지 않아서 추천은 못드리겠습니다. 맞든 아니든 누군가 명쾌하게 제게 답을 내려줬으면 좋겠습니다..

'Spring' 카테고리의 다른 글

스레드풀 전략  (0) 2025.05.02
서블릿 컨테이너의 이해  (0) 2025.04.04
스프링 시큐리티의 구조와 대체 방안  (3) 2025.01.02
스프링 부트에서 예외와 처리 방법  (2) 2024.12.30
Spring Security 필터에서 발생한 인증/인가 예외 처리하는 방법  (5) 2024.12.30
'Spring' 카테고리의 다른 글
  • 스레드풀 전략
  • 서블릿 컨테이너의 이해
  • 스프링 시큐리티의 구조와 대체 방안
  • 스프링 부트에서 예외와 처리 방법
onetaek
onetaek
finding-scholarship.vercel.app
  • onetaek
    원택투택
    onetaek
  • 전체
    오늘
    어제
    • 전체 (23)
      • Spring (13)
      • Docker (1)
      • Redis (3)
      • Study (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 숨은 장학금 찾기 사이트
  • 공지사항

  • 인기 글

  • 태그

    RDMBS
    Spring
    컴퓨터 구조
    No SQL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
onetaek
엔티티 DTO 변환 위치
상단으로

티스토리툴바