카테고리 없음

220526 DTO(Data Transfer Object)

Vince_rf 2022. 5. 26. 15:10

DTO(Data Transfer Object)


Entity를 통해 DB에서 데이터를 꺼내왔지만 한가지 문제가 있다.
요청을 받고 데이터를 처리하고 반환해주기 위해선 데이터에 접근해야 하는데
여기서 Controller, Presentation Layer의 경우 클라이언트와 직접 맞닿는 부분이고
엔티티는 프레젠테이션 계층과 완전히 분리되어야 한다

이럴 때 DTO를 사용하는데

    @Data
    @AllArgsConstructor
    static class MemberDto {
        private String name;
        private Address address;
    }
  • Getter/Setter 없음
  • Wrapping 된 순수한 데이터 객체
  • 엔티티에 직접 접근하지 않기때문에 엔티티가 변경되어도 DTO만 변경하면 된다

 

DTO가 없으면? DTO를 왜 쓰는가?

1) Entity클래스와 거의 유사한 형태임에도 DTO 클래스를 추가로 생성하는 이유는 Entity 클래스가 데이터베이스와 맞닿은 핵심 클래스이기 때문입니다.

 

Entity 클래스를 기준으로 테이블이 생성되고 스키마가 변경되는데, 화면 변경과 같은 사소한 기능 변경을 위해 테이블과 연결된 Entity 클래스를 변경하는 것이 너무나 큰 변경이 되는 것이죠.

 

또한 View Layer와 DB Layer 역할 분리를 철저히 하는 것이 좋은데, 실제로 Controller에서 결과값으로 여러 테이블을 조인해서 줘야 할 경우가 빈번하기 때문에 Entity 클래스만으로 표현하기 어려운 경우가 많습니다.

 

2) 다양한 비즈니스 로직과 요구사항에 대해 유연하게 대응할 수 있습니다.

 

파라미터로 엔티티 자체를 받게 되면 엔티티에서 정해진 포맷에 맞춰 개발을 해야합니다. 하지만 DTO는 각 비즈니스 로직에 맞춘 필드들만 생성함으로써 DTO를 보면 어떤 값들이 매핑되는지 쉽게 파악할 수 있고, 만약 API 설계 상황에서 필드에 다른 이름을 부여하거나 하는 상황에서도 유연하게 대처할 수 있습니다.

 

3) Controller와 Service 사이에서 강한 의존을 방지하기 위해서 DTO를 사용합니다.

Service가 받고 싶은 파라미터가 Controller에게 종속적이게 되면 Service가 Controller 패키지에게 의존하게 됩니다. 따라서 이를 방지하기 위해서라도 Service가 원하는 포맷에 맞춰 Controller 딴에서 DTO를 통해 그 포맷을 맞춰주는 것입니다.

 

4) Service 레이어가 모듈로 분리되어버리면 해당 Type을 쓸 수 없게 됩니다.

 

5) 트랜잭션으로 처리되어야 하는 DTO 항목이, 항상 요청으로 들어온 결과값과 동일하지 않을 수 있습니다. 아래 그림을 예로 들어보겠습니다.

 

 

위 그림에서 사용자 요청의 파라미터를 통해 외부 API를 여러번 호출한 이후 Service 레이어를 호출하는 경우, Controller가 받은 Web DTO와 Service가 받아야 할 DTO가 달라집니다.

 

외부 API 호출뿐만 아니라 Client 요청 이후 Service 레이어를 호출하기 전 다른 작업으로 인해 데이터 포맷이 달라질 수도 있겠죠.


이런 경우에 Service 레이어가 Controller 레이어 DTO에 의존하고 있다면 문제가 될 수 있습니다. 따라서 Service 레이어는 자신이 원하는 포맷으로 데이터를 받을 수 있어야합니다.

 

참고로 위의 예제에서 Controller에서(Controller-Service사이에 중간 레이어를 두고 하는 경우 포함) 외부 API를 조회하는 이유는 Service에서 해당 작업을 수행하는 경우 트랜잭션과 무관한 작업이 트랜잭션내에 포함되기 때문에 DB 타임아웃과 같은 이슈가 발생할 수 있기 때문입니다.

 

이러한 문제를 해결하기 위해서는 Service는 자신이 원하는 포맷에 맞게 데이터를 받고, Controller에서 그 포맷을 만들어주는 것이 필요합니다.

 

하지만...


여러 글들을 읽어보면서 DTO를 어느 영역에서 어느정도로 사용해야 하는가에 대한 대답은 여러가지였던 것 같습니다.

 

특히 'DTO의 사용 목적은 클라이언트와 Controller layer 간 중계만 담당하는 것이기 때문에 Service layer로 넘어가는 객체는 DTO가 아닌 Entity 객체여야 한다.'는 주장도 있었습니다.

 

하지만 제 생각으로는 서비스 로직에서 어떤 작업을 할 때 Entity가 2개 이상 필요하다고 하면, Controller에서 여러 Entity들을 한 데 모은 DTO를 서비스에 넘겨주면 되기 때문에 컨트롤러가 서비스에 의존적이지 않게 될 수 있다는 장점이 있다고 생각합니다.

 

또한, DTO를 서비스에 넘기지 않으면 Response에 포함될 필요가 없는 필드까지 Controller에 다시 ResponseDto로 돌아가게 된다는 점에서 문제가 생긴다고 생각합니다.

 

결론적으로 정리하자면, 서비스는 자신이 원하는 포맷을 기다리고 있으면 되고 컨트롤러에서 DTO를 생성하여 서비스에게 넘겨주면 된다고 생각합니다 그리고 서비스는 해당 DTO를 비즈니스 로직을 거쳐 ResponseDto를 다시 던져주면 되겠죠. 

 

출처 : https://velog.io/@agugu95/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8C%A8%ED%84%B4%EA%B3%BC-DAO-DTO-Repository

 

 

스프링과 DAO, DTO, Repository, Entity

스프링을 사용한 웹앱의 경우 DAO, DTO, Entity를 사용하여 데이터를 다룬다.

velog.io

https://studyandwrite.tistory.com/402

 

[스프링/Spring] DTO는 왜 써야 하나?

1. 고민? DTO(Data Transfer Object)란 계층간 데이터 교환을 위해 사용하는 객체(Java Beans)입니다. 아래 코드를 보면서 DTO는 왜 필요한가에 대해 생각해보겠습니다. * 실제 엔티티 설계의 일부입니다. 위

studyandwrite.tistory.com