DTO의 적절한 사용에 대한 고민

Tina Jeong·2020년 8월 25일
1

이때까지 나는 DTO를 Repostiory에서 생성 및 매핑 후 Service에서 포맷팅하고 Controller에서 그대로 return하는 방식으로 사용했다. Repository에서는 아래와 같이 사용했다.

   JPAQuery<PersonDTO> personDTOJPAQuery = jpaQuery.clone()
        .select(Projections.constructor(PersonDTO.class,
            person.personId,  person.nickName,
            person.birthday));

의문: DTO가 서버 레이어 전반에서 쓰이는 게 맞는가?

DTO의 정의가 레이어간 이동시 데이터를 담는 객체라는 정의도 있었지만, 프로세스 간 데이터 이동 시 데이터를 담는 객체라는 말을 보아서 의아했다. Controller - Service - Repostiory 각각 프로세스가 올라간다는 말을 들어본 적이 없었기 때문이다. 또, JPA 스펙에서 Entity 객체는 언제 쓰이게 되는지도 의문이었다.

Entity to DTO conversion in Controller

그러다 다른 springboot 프로젝트 코드들을 보다가 DTO로의 변환이 컨트롤러에 일어난다는 것을 알게 되었다. Repository와 Service에서는 Entity 형태로 데이터가 다루어지다가, 컨트롤러에서 변환된 DTO 객체가 클라이언트단으로 반환되는 구조였다. 그렇다면 서버/클라이언트가 각각의 레이어/프로세스로 명명되는 것이 더 reasonable하다고 여겨졌다.(이와 별개로, 프로세스/레이어간 이동이라는 말 자체가 애매하다는 생각도 든다.)

@GetMapping
@ResponseBody
public List<PostDto> getPosts(...) {
    //...
    List<Post> posts = postService.getPostsList(page, size, sortDir, sort);
    return posts.stream()
      .map(this::convertToDto)
      .collect(Collectors.toList());
}

baeldung 예시에서도 Controller에서 변환을 시도한다. (출처: https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application)

DTO를 사용하는 이유?

Controller에서 변환을 하는 것은 DTO를 사용하는 이유와 관련이 있다고 생각한다.

1. remote method의 multiple calls를 방지

일반적으로 클라이언트는 엔드 포인트를 호출해서 정보를 받아온다. 필요한 정보를 얻기 위해 서버에 여러번 요청을 보내야 한다면 서버의 부하가 커질 수 밖에 없다.

2. Entity의 외부 노출을 막기 위해

Entity가 외부에 노출되면 비번 같은 사용자 민감 정보 등이 노출될 수 있다. 무결성이 보장되지 못한다.

즉, DTO는 클라이언트가 꼭 필요한 정보 만을 담고 있는, View단을 위한 데이터 객체이기 때문이다. 그래서 컨트롤러에서의 DTO 변환이 DTO의 원론적 의미에 맞는 사용법이라는 생각이 든다.

DTO, VO, Entity의 적절한 사용에 대한 고민은 계속된다!

그렇다고 DTO를 서버레이어 전반에서 사용하는 예시가 잘못됐다고 말할 순 없다. 요구사항이 거의 변경되지 않는다면 DTO를 레포단에서 생성할 수 있다고 생각한다. Entity 객체를 추가적으로 사용할 필요가 없어 오히려 유지보수가 쉬워질 수도 있다.

또는 레포단에서만 Entity를 사용하고 Service단에서 변환하는 예시도 좋은 것 같다. 다만 맥락에 맞게 DTO / VO / Entity를 사용하기 위해서는 고민이 꼭 필요하다. 그냥 사용할게 아니라!

Integrity, Immutability와 데이터 객체의 연관성에 대한 논의가 아주 많다. 더 공부를 하고 다른 포스팅에서 정리해봐야겠다.

profile
Keep exploring, 계속 탐색하세요.

1개의 댓글

comment-user-thumbnail
2021년 3월 31일

글 잘 읽었습니다. 항상 Entity <-> DTO를 변환하는 타이밍을 고민해 왔었는데, 한층 도움이 된 것 같습니다.
한가지 궁금한 점이 있습니다. Service에서 리턴되는 Entity A가 다른 Entity B를 LazyLoading으로 참조하고 있다 가정했을 때, DTO를 변환하는 과정에서 두 entity의 정보를 모두 담아야하는 상황에는 어떻게 해결하시는지요?

답글 달기