[Spring] DTO의 사용 범위에 대하여

김우진·2021년 11월 9일
0
post-thumbnail

이 글은 Dto를 사용하면서 어떻게 해야 잘 사용할 수 있지? Domain으로는 언제 변환하는 것이 맞지? Dto를 내가 잘 사용하고 있나? 등의 궁금증을 해결하기 위한 글입니다. 틀린 부분이 있을 수 있습니다. 가져온 글의 출처는 아래에 있습니다.

DTO(Data Transfer Object)

DTO는 계층간 데이터 교환을 위해 사용하는 객체다.

이 그림처럼 3-Layer-Architecture를 예시로 들었을 때 DTO는 계층에 해당되지 않고 각 계층간에서 데이터 교환을 위해서 서로 상호작용하는 대상이라 생각하면 된다.

Layered Architecture의 DTO 사용

Layered Architecture는 유사한 관심사들을 레이어로 나누고 추상화하여 수직적(수평적으로도 가능)으로 배열하는 아키텍처이다. 하나의 레이어는 자신에게 주어진 고유한 역할을 수행하는 것에 집중하고, 인접한 다른 레이어 하고만 상호작용한다. 즉, 응집도는 높히고 결합도는 낮춰 재사용성과 유지보수성(시스템 전체를 수정하지 않아도 됨)을 높이는 아키텍처입니다.

이 Layered Architecture를 조금 더 잘 사용하기 위해 같이 사용하는 것이 DTO라고 생각하면 된다. 그러면, 이 DTO는 어떨 때 사용하면 될까?

Presentation Layer에서 Dto 사용과 변환

-----------------
ArticleController
-----------------
@PostMapping
public ResponseEntity<ArticleResponseDto> createArticle(@RequestBody ArticleRequestDto articleRequestDto) {
    //로직 생략
    Article article = articleRequestDto.toEntity();
    Article savedArticle = articleService.createArticle(article);
    ArticleResponseDto articleResponseDto = ArticleResponseDto.from(savedArticle);
    return ResponseEntity.ok().body(articleResponseDto);
}
--------------
ArticleService
--------------
public Article createArticle(Article article) {
    //로직 생략
    return articleRepository.save(article);
}

위 코드는 아래와 같은 로직을 가진다.

  1. Client로 부터 받아온 데이터를 @RequestBody를 통해 Dto로 매핑하고, 이 Dto를 Controller에서 Domain(Entity)으로 변환하고 Service 레이어에게 전달하여 작업을 수행
  2. Service 레이어는 Controller에게 Domain을 반환하고, Controller는 Domain을 Dto로 변환해서 Client에게 응답을 보낸다.

그런데, 이 Dto와 Domain간의 변환 위치가 Controller가 맞을까?

Business(Service) Layer에서 Dto 사용과 변환

아래 코드처럼 Service 레이어에서 Dto를 Domain으로 변환하여 사용해도 동작에 문제가 없다.

public ArticleDto createArticle(ArticleDto articleRequestDto) {
    Article article = articleRequestDto.toEntity();
    //로직 생략
    return ArticleDto.from(articleRepository.save(article));
}

그러면 위에서 설명하길 Dto는 계층간 데이터 전달을 위해 사용하므로 Controller에서 Service로 데이터를 보낼때 Dto를 통해서 보내고 Service 레이어에서 변환해주는 것이 맞는 것 같다. 또한 복잡한 어플리케이션의 경우 Client로 받아오는 Dto 만으로 Entity를 구성하기는 어려울 수 있으므로 Repository를 통해 부수적인 정보들을 조회할 필요가있는데 그러려면 Data-Access 레이어와 상호작용이 가능해야 하므로 Service 레이어에서 해주는 것이 조금 더 설득력 있어 보인다.

실제로 마틴 파울러는 Service 레이어란 어플리케이션의 경계를 정의하고 비즈니스 로직 등 도메인을 캡슐화하는 역할이라고 정의한다. 즉, 도메인을 Presentation 레이어에서 사용하여 Controller의 변경이 도메인의 변경으로 이어지는 것을 막아야 한다는 것이다.

Martin Fowler
A Service Layer defines an application’s boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers. It encapsulates the application’s business logic, controlling transactions and coor-dinating responses in the implementation of its operations.

이러한 관점에서 바라보면 레이어 간 데이터 전달 목적으로 Dto 사용을 고수한다면 변환되는 로직이 Service 레이어에서 정의되야 하는 것이 맞는 것 같다.

그러면 Repository 즉, Data-Access 레이어에선 변경하는 것 어떨까?

Data-Access(Repository) Layer에서 Dto 사용과 변환

Repository 레이어는 Entity의 영속성을 관장하는 역할이다. 이로 인해 Repository 레이어에서 Dto 변환하는 작업에 대한 책임을 하는 것은 지양하는 것이 좋아보인다.

”…a cohesive set of responsibilities for providing access to the roots of AGGREGATES from early life cycle through the end” - Evans

그렇다면 Service에서 사용하는 것이 정말 좋을까? 아래 출처의 글의 마지막처럼 Service 레이어에 DTO가 들어오면 안된다고 생각하시는 분들도 많다.

결국, 아직까지 답은 없는 것 같다. 다만, 좋은 코드 작성을 위해서 꾸준히 고민하는 것은 필요로 해 보인다. 나도 나만의 코드 방식을 계속 회고하며 발전시키는 것을 목표로 해야겠다.

출처

  1. 3기_케빈님의 blog: DTO의 사용 범위에 대하여

썸네일 출처

unsplash페이지의 Brett Jordan님

0개의 댓글