중첩 DTO vs Flat DTO

김현정·2025년 5월 28일
0

Spring Boot로 REST API를 개발하면 ResponseDto부분에서 필요한 부분을 리스트 형식으로 가져오는지
어떻게 가져올지 고민을 하는데 이번에는 중첩 DTO를 사용해보았다.

1. 중첩 DTO (Nested DTO) 방식

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TrainerReservationResponseDto {
    private Long reservationId;
    private LocalDate reservationDate;
    private LocalTime reservationTime;
    private ReservationStatus status;
    
    private GymInfo gym;
    private UserInfo user;

    @Getter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class GymInfo {
        private Long gymId;
        private String name;
        private String address;
        private String number;
    }

    @Getter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class UserInfo {
        private Long userId;
        private String name;
        private String email;
        private String phone;
    }
}

JSON 응답 예시:

{
  "reservationId": 1,
  "reservationDate": "2025-06-01",
  "reservationTime": "15:00",
  "status": "CONFIRMED",
  "gym": {
    "gymId": 1,
    "name": "피트니스센터",
    "address": "서울시 강남구",
    "number": "02-1234-5678"
  },
  "user": {
    "userId": 1,
    "name": "홍길동",
    "email": "hong@example.com",
    "phone": "010-1234-5678"
  }
}

2. Flat DTO 방식

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TrainerReservationFlatDto {
    private Long reservationId;
    private LocalDate reservationDate;
    private LocalTime reservationTime;
    private ReservationStatus status;
    
    // Gym 정보
    private Long gymId;
    private String gymName;
    private String gymAddress;
    private String gymNumber;
    
    // User 정보
    private Long userId;
    private String userName;
    private String userEmail;
    private String userPhone;
}

JSON 응답 예시:

{
  "reservationId": 1,
  "reservationDate": "2025-06-01",
  "reservationTime": "15:00",
  "status": "CONFIRMED",
  "gymId": 1,
  "gymName": "피트니스센터",
  "gymAddress": "서울시 강남구",
  "gymNumber": "02-1234-5678",
  "userId": 1,
  "userName": "홍길동",
  "userEmail": "hong@example.com",
  "userPhone": "010-1234-5678"
}

비교 분석

구분중첩 DTOFlat DTO
가독성논리적 구조 명확필드가 많아지면 복잡
타입 안전성강함 (내부 클래스)약함 (필드명 혼재)
재사용성높음 (GymInfo 재사용 가능)낮음
JSON 크기약간 큼 (중첩 구조)작음
파싱 복잡도중간낮음
확장성좋음나쁨

중첩 DTO의 장점

  1. 명확한 의미적 그룹핑
// 체육관 정보만 필요할 때
GymInfo gymInfo = reservation.getGym();
String gymName = gymInfo.getName();
  1. 뛰어난 재사용성
// 다른 DTO에서도 동일한 구조 재사용
public class GymDetailResponseDto {
    private GymInfo gym;  // 재사용!
    private List<TrainerInfo> trainers;
}
  1. 타입 안전성 보장
// 컴파일 타임에 오류 검출
reservation.getGym().getName();  // ✅ 안전
reservation.getGymName();        // ❌ 오타 가능성

4.쉬운 확장성

public static class GymInfo {
    private Long gymId;
    private String name;
    private String address;
    private String number;
    // 새 필드 추가 시 여기만 수정하면 됨
    private String description;
    private List<String> facilities;
}

중첩 DTO의 단점

  1. JSON 크기 증가
// 중첩: 더 많은 브래킷과 키
{"gym": {"gymId": 1, "name": "..."}}

// 평면: 더 간결
{"gymId": 1, "gymName": "..."}
  1. 프론트엔드 접근 복잡도
// 중첩: 한 단계 더 접근
const gymName = reservation.gym.name;

// 평면: 직접 접근
const gymName = reservation.gymName;

상황에 따른 선택

중첩 DTO를 선택

✅ 관련 필드가 많고 논리적 그룹핑이 가능할 때
✅ 코드 재사용성이 중요할 때
✅ 도메인 구조가 복잡할 때
✅ 장기적 확장 가능성이 높을 때
✅ 타입 안정성이 중요한 프로젝트

Flat DTO를 선택

✅ 필드 수가 적을 때
✅ 성능이 매우 중요할 때 (모바일 앱)
✅ 단순한 CRUD 작업
✅ 레거시 시스템과의 호환성이 필요할 때

0개의 댓글