NestJS, SpringBoot 등의 프레임워크를 사용할 때마다 DTO를 사용했었다. DTO가 무엇인지, 왜 사용해야하는지 등에 대한 고민은 뒤로하고 항상 다 사용하니까 나도 따라 사용했다. 그렇다면 DTO란 무엇이고, 왜 사용해야할까?
In the field of programming a data transfer object (DTO) is an object that carries data between processes. - Wiki
위키백과에서 말하는 DTO는 프로세스 간 데이터를 전달하는 객체 라고 정의되어 있다. 이 뜻을 다시 내 입맛대로 재정의해보자. DTO는 순수하게 데이터를 전송하기 위해 사용하는 객체이며, 서버 - 서버, 서버 - 클라이언트 간 데이터 전송에 사용된다.
사진 출처 :
직접 API를 개발하다보면 특히, express 등의 프레임워크를 사용하여 개발을 하면 DTO의 존재에 대해서 알지 못한채 개발을 하게 된다. 그냥 Controller 단에서 body 객체를 받아 변수에 저장하면 끝이니까. 나도 그렇게 사용했었고 NestJS나 SpringBoot를 사용하면서 DTO를 왜 굳이 사용해야 하나 싶기도 했다. 그래서, 왜 사용하는지는 알고 내가 사용해야 덜 찝찝하고 귀찮게 설계하는 것에 대한 이유가 생길 것 같았다.
- DTO와 Entity의 분리
- 효율적인 Validation 가능
- reqeust, response 시 필요 데이터만 전송해 효율성 증가
일단 내가 사용하면서 느낀 이유와 여러 문서에서 찾은 DTO의 사용 이유를 크게 3가지로 정리해보았다. 각각의 내용을 조금 면밀하게 다루어보자.
DTO와 Entity를 분리한다는 것은 DB Layer와 View Layer의 역할을 분리한다는 것으로 받아들일 수 있다.
Entity는 실제 Table과 매핑되어 있는데, 비즈니스 요구사항에서 가장 자주 변경되는 View Layer에서 Entity를 사용할 경우 Entity를 그 요구에 맞게 계속 변경하는 것은 바람직하지 않다. 그 이유로는 Entity 클래스가 변경되면 다른 클래스에도 영향을 미치게 되기 때문이다.
또, DTO 대신 Entity를 사용하게되면 Entity의 구조가 외부에 노출될 수 있는데 이는 보안적으로 문제가 될 수 있다. 그래서 DTO를 사용함으로써 Entity 내부 구현을 캡슐화할 수 있다.
사실 Validation은 Entity에서도 수행할 수 있다. 그렇지만, 서버 내부 로직을 타기 전, DTO에서 먼저 Data에 대한 Validation을 수행하게 된다면 성능적인 측면에서 더 효율적이다. 그렇다고 해서, DTO에서만 Validation을 수행하는 것은 바람직하지 않다. Validation은 서버로 Data를 전달하기 전, Front 단에서도 진행되어야 하고, DTO, Entity 클래스에서도 전부 진행되는 것이 가장 안전하다.
여러 API에서 요구하는 데이터는 각각 다르고, reqeust/response에서 필요한 데이터도 다를 수 있다. 이런 경우, Entity를 통해 데이터를 전송하게 되면 사용하지 않는 데이터까지 전부 보내게 되는데, 이는 효율적이지 못하고 아까 말했듯 Entity 구조를 외부에 노출하게 된다.
DTO를 사용함으로써, 다양한 API 형태에 맞추어 필요한 데이터만 전송하여 전송 속도를 개선하고 효율성을 높일 수 있다.
DTO를 왜 사용해야 하는지, 어떤 식으로 사용이 되는지 등에 대해서 알 수 있었다. 사실 최근 진행한 프로젝트에서 DTO 설계를 하다가 정말 포기할 뻔 했었는데, Entity를 직접 사용하게 되었을 때 나중에 생길 기술 부채를 생각해보면 DTO 설계에 든 비용이 훨씬 값싸다고 판단이 되었다.