1
2
3
4
5
public record BenefitDto(EnumMap<DiscountPolicy, Integer> discountResults, BenefitFood benefitFood) {
public static BenefitDto create(EnumMap<DiscountPolicy, Integer> discountResults, BenefitFood benefitFood) {
return new BenefitDto(discountResults, benefitFood);
}
}
우테코 프리코스 4주차 미션을 하면서 DTO를 처음 적용해보았다.
DTO에 대해 잘 몰랐는데, View에 보낼 데이터가 Model의 데이터와 달라 Model을 직접 보내기엔 데이터의 값을 View에서 계산한다면 View의 책임에 위배되는 것 같아 DTO를 사용하게 되었다.
그래서 DTO에 대해 정리해보려고 한다.
DTO란?
DTO는 Data Transfer Object의 약자로 계층 간 데이터 교환을 하기 위한 목적으로 사용된다.
DTO가 생긴 이유는 Client와 직접 상호작용하는 Controller에서 DB와 연관된 Entity를 직접 사용하지 않고, 데이터만 가져오기 위함이다.
DTO는 단지 데이터를 교환하기 위한 목적이므로, 다른 로직이 필요하지 않다. 상속도 하지 않아야 한다.
보통 getter, setter와 같은 메서드만 구현되어 있다. 그래서 나도 record를 사용하게 된 것이다.
결국 DTO는 Model과 View 사이의 결합을 떨어뜨리기 위해 나온 것이다. 그렇다면 Model과 View가 강한 결합이 되어 있을 때 어떤 문제가 발생할 수 있을까?
Model과 View(UI)의 결합 문제
- 도메인 Model의 모든 속성이 외부로 노출된다.
- 각 View마다 사용하는 Model의 정보는 다를 수 있다. 하지만 Model 객체는 해당 UI에서 사용하지 않는 불필요한 데이터까지 보유하고 있다.
- 비즈니스 로직과 같이 도메인 내부에 있는 중요한 정보가 외부에 노출된다는 보안과 관련된 문제가 발생할 수 있다.
- UI 계층에서 Model의 메서드를 호출하거나 상태를 변경할 위험이 있다.
- Model과 View가 강하게 결합되면 View의 요구사항 변화가 Model에 영향을 끼칠 수 있다.
- View에 필요한 데이터를 얻기 위해 Model의 로직을 변경하는 경우가 생길 수 있다.
이러한 문제를 DTO를 사용했을 때 쉽게 해결할 수 있다. 도메인 모델을 캡슐화하고 View에서는 View에서 사용할 데이터만 선택적으로 보낼 수 있다.
웹 환경에서의 DTO
웹 환경, Spring에서의 DTO를 생각해본다면 도메인 모델(Entity) 대신 DTO를 사용하게 되는 것이다.
관심사의 분리
엔티티는 Data Access 계층에서 데이터가 저장되는 DB와 직접적으로 연관되어있는 객체이다. 따라서 테이블 구조에 맞게 설계되는 엔티티는 초기 설계 후 최대한 수정되지 않는 것이 안정적인 모델이다.
엔티티에는 비밀번호나 개인 정보같은 노출되어서는 안되는 민감한 정보들까지 포함되어 있다.
그에 비해 Presentation 계층에서는 View의 요구 사항에 따라 전달되는 데이터의 구조가 자주 바뀐다.
즉, 각 계층의 관심사가 다르다는 것이다.
- Presentation 계층 : 애플리케이션의 기능과 데이터를 사용자에게 제공
- Business 계층 : 애플리케이션의 핵심 비즈니스 로직 및 Data Access 계층과 Presentation 계층간에 전달되는 데이터의 처리
- Data Access 계층 : 데이터베이스와 상호 작용
DTO는 Presentation 계층에 속하는 것이다. 데이터의 전달이 주 목적이기 때문이다.
반면 엔티티는 핵심 비즈니스 로직을 담는 비즈니스 영역의 일부이다. 따라서 엔티티는 그에 따른 비즈니스 로직이 추가될 수 있고, 이는 다른 계층 사이에서 데이터의 전달을 위해 사용되는 객체가 아니라는 뜻이다.
단, DTO의 사용범위와 엔티티와 DTO를 어느 계층에서 변환시키는 것이 합리적인 것인지에 대해서는 의견이 다양하기 때문에 고민이 필요하다.
클라이언트로부터 서버(Controller)의 호출을 최소화 하기 위함
어떤 상품 Q&A 페이지에서 View를 구성하기 위해서는 아래 API를 호출해야만 한다고 가정해보자.
- 상품소개 API
- Q&A API
- 유저 API
서버와 클라이언트가 3번의 통신을 해야만 하는 구조이다.
DTO를 사용하면 한 번의 호출로 여러 매개변수를 일괄 처리하여 서버의 왕복을 줄일 수 있다.
이 과정에서 DB에 접근하는 횟수는 같고, 엔티티를 DTO로 변환하는 과정이 번거롭고 중복코드가 발생한다는 문제가 발생할 수 있다.
하지만 위와 같은 문제를 감수하더라도 서버와 클라이언트 사이의 호출 비용이 더 크기 때문에 DTO를 사용하여 개선할 수 있다고 보는 것이다.
참고할만한 포스트
( DTO의 사용 범위에 대해서는 답이 있는 것은 아니기 때문에 내가 프로그램을 구현해보면서 DTO를 조금 더 사용해 본 뒤 직접 경험해본 후 고민해보아야 할 것 같다. )