Supabase 환경에서는 왜 DTO를 따로 정의하지 않을까?
기존 흔히 익숙한 전통적인 백엔드 환경(NestJS, Spring 등)에서는 DTO가 필수입니다.
여기서 DTO는 Data Transfer Object로 계층 간에 데이터를 전달하기 위해 사용하는 객체(Object)를 말합니다.
왜 DTO가 필수일까요?
앞서 말씀드린 ‘전통적인’ 백엔드 환경에서는 데이터베이스의 테이블과 매핑되는 Entity(엔티티) 클래스가 존재합니다.
Entity 클래스 내부에는 @Column, @ForeignKey, @Index, 등 같은 DB 구동을 위한 복잡한 코드와 설정들이 들어가 있기 때문에 이걸 클라이언트에 그대로 내보내면 문제가 발생합니다.
영속성 관심사 분리
- 비밀번호, 주민번호같은 민감한 필드가 그대로 api 응답으로 노출될 위험이 있다.
- database 테이블 구조를 바꾸는 순간, 프론트엔드가 받는 api 스펙까지 강제로 깨져버린다.
필요한 데이터가 다르다
- 사용자 엔티티는 필드가 20개인데, 특정 화면에서 막상 필요한 데이터는 2개뿐이다.
따라서 DTO를 만들어서 필요한 데이터만 골라서(TypeScript의 ‘Pick’/‘Omit’) 내보내는 과정을 거칩니다.
하지만, Supabase에서는 얘기가 다릅니다.
현재 진행중인 “MENHERING” 프로젝트는 Supabase를 쓰고 있고, 이 Supabase는 ‘전통적인’ 백엔드 서버와 데이터 흐름이 완전히 다릅니다.
간단하게 소개해드리면,
- Entity 클래스 자체가 없다.
앞서 말씀드린 전통적인 백엔드와 다르게, Supabase에서는 직접 class UserEntity { ... }와 같은 복잡한 백엔드 코드를 짜지 않습니다. 대신 테이블 모양 그대로 생긴 단순한 JSON 객체 row가 결과로 나옵니다.
- Supabase가 자체적으로 필드를 필터링해준다.
앞서 말씀드린 두 번째 이유가 됐던 화면마다 다른 필드가 필요할 때, Supabase는 굳이 백엔드 코드 단에서 Pick/Omit 같은 타입 변환 도구를 쓰지 않아도 됩니다.
이러면 프론트엔드나 중간 레이어에서 타입을 쪼개고(types/ or schemas/) 결합하는 복잡한 설계와 이점이 대폭 줄어듭니다.
“그러면 무조건 Supabase를 써야겠네!”
그건 아닙니다. 결국 “Silver Bullet“은 없는 법이죠.
분명 Supabase는 위와같은 귀찮은 작업을 없애주고, 프론트엔드 개발자에게 엄청난 생산성을 준 만큼, DB 구조가 비즈니스 로직과 매우 밀접하게 맞닿아있어, 서비스 규모가 커지고, 비즈니스 규칙이 많아질수록 유지보수에 엄청난 어려움을 겪을 수 있습니다.
따라서 프로젝트의 규모와 도메인 복잡도를 고려해 적합한 아키텍처 선택을 해야 하는 것이 앞으로도 가장 중요한 문제이지 않을까 생각합니다.
- #배움일기
- #Supabase