인프런 김영한 강사님 강의를 듣고 정리한 내용입니다.
Data Transfer Object
Form, API에서 저장 요청 시 특정 엔티티를 파라미터로 받게 되거나, 조회 요청 시 엔티티를 반환해야하는 경우가 발생한다.
하지만 실제 엔티티 클래스 객체를 파라미터로 받거나 반환하는 대신 거의 대부분 DTO
라는 특별한 객체가 사용된다. DTO의 사용은 권장이 아닌 필수라고 할 정도로 강제되는데, 왜 DTO를 사용해야할까?
요청에서 검증 과정이 필요할 수 있다. 엔티티의 Validaiton
은 주로 @Valid, @Validated
어노테이션을 통한 검증으로 이루어진다. 검증이 필요한 필드들에 @NotEmpty, @NotNull
등의 검증사항을 붙여주게 된다.
그런데, Entity 클래스 자체에 이러한 검증사항을 붙여주는 경우 문제가 된다.
문제가 되는 이유는 다음과 같다.
1. 도메인은 많은 범위에서 쓰이게 되므로 변동 가능성이 크다.
=> 엔티티의 수정이 일어날 경우, 그 엔티티를 사용하게 되는 모든 API의스펙을 변경해야하는 문제점이 있다.
2. 프레젠테이션 계층(Presentation Layer)에서 필요한 검증 로직을 엔티티 내부에 붙이는 것은 문제가 된다.
=> 특정 API에서는 검증 과정이 필요할 수도 있지만 다른 API에서는 필요하지 않을 수 있다.
문제가 되는 이유는 다음과 같다.
1. 응답 스펙을 맞추기 위해 로직이 추가된다.
=> 엔티티 내부에 다른 엔티티가 있는 경우, 필요하지 않은 정보까지 모두 조회하게 된다. 그래서 @JsonIgnore 과 같이 추가적인 설정을 해주어야하는데, 다른 API에서는 필요하지 않을 수 있다.
2. List로 API 스펙이 굳어질 수 있다.
=> 서비스에서 조회 기능은 Entity 클래스 타입 List를 반환한다. 이 List를 그대로 response하게 되는 경우에, List 내부에는 다른 값을 같이 넣어서 보낼 수가 없다.
3. 웹에 엔티티 자체를 노출하게 되는 문제 발생
=> 극단적인 경우로는 password를 노출하게 될 수도 있다.
4. API 스펙 상 필요없는 정보까지 모두 끌어오게 되어 성능 악화
문제 발생
그렇기 때문에 API 스펙을 위한 별도의 DTO(Data Transfer Object)
를 사용해야 한다.
DTO 클래스를 만들고, 요청에서 파라미터를 받을 때도 Entity 객체 대신 DTO 객체를 받는다. 그리고 Entity를 외부에 노출시키지 않는다.
1. DTO만 보고 API 스펙의 요구사항을 알 수가 있다.
=> 예를 들어 어떤 API에서는 name만 요구한다면, 해당 API의 DTO 내부에는 name 필드만 정의되어 있을 것이다. 또한 DTO는 해당 API의 Validation 요구사항에 딱 맞추어 설계된다.
2. Entity가 수정되더라도 API 스펙의 변경이 일어날 일이 없다.
=> Entity의 name 필드가 username이라는 이름으로 변경되어도, DTO에서는 여전히 name이라는 이름으로 필드를 받기 때문에 API 스펙은 변경되지 않는다.
결론적으로 DTO의 사용은 Entity와 API 스펙 간의 명확한 분리
를 하여 유지보수
에 있어서 매우 큰 장점으로 작용한다.
또한 Entity 클래스 객체를 그대로 사용했을 때 발생할 수 있는 무수한 Side Effect를 방지할 수 있다.