카테고리 없음

Spring DTO는 어디까지 사용?

코딩연습중 2025. 4. 21. 18:47

https://stella-ul.tistory.com/entry/DTO%EC%9D%98-%EC%82%AC%EC%9A%A9%EB%B2%94%EC%9C%84%EB%8A%94-%EC%96%B4%EB%94%94%EA%B9%8C%EC%A7%80-%EB%98%90-DTO-%EB%B3%80%ED%99%98%EC%9D%80-%EC%96%B4%EB%94%94%EC%84%9C

 

DTO의 사용범위는 어디까지? 또, DTO 변환은 어디서?

전에 Controller와 Service 계층 간 데이터 전달을 어떻게 해야 좋을지에 대한 포스팅을 작성했었다. 뭔가 숲보다 나무를 먼저 본? 느낌이긴한데... 하하; 그때 배우던 예제에선 Service가 Entity를 반환했

stella-ul.tistory.com

(위의 글을 읽고 공부해봄)

 

 

많은 글을 보면 DTO는 Repository 영역까지 들어오면 안 되고, Service 영역까지만 사용해야 한다고 한다. Repository에 접근하는 건 Entity만 가능하도록 설계하는 게 좋다고..

 

DTO의 역할은 계층 간 데이터 전달을 위한 객체이며, Repository에서는 도메인(Entity)만 다뤄야 한다는 건 많이 들어서 알고있다.

DTO와 Entity의 역할 및 목적은 명확히 다르다.

 

Repository에서 DTO를 사용을 지양하는 이유는 다음과 같다.

 

Repository의 DTO 사용 지양 이유

1. 계층 간 의존성 방향 문제

만약 Repository가 DTO를 쓰게 된다면?

DTO가 아래 계층(Repository)에 침투하게 되어 Controller/Service가 변경된 경우, -> Repository까지 변경해야 할 수 있다.

이로 인해 결합도가 상승하고, 유지보수성이 떨어진

 

2. DTO는 비즈니스 로직을 표현할 수 없다. 

Repository는 보통 쿼리 기준으로 설계되지만, DTO는 UI 맞춤형 구조이기 때문에 도메인 모델과 안 맞을 수 있다. 

 

3. DTO는 계층 간 독립성을 지켜야 한다. 

잘못된 예시를 살펴보겠다. 

public interface ReservationRepository {
    List<ReservationListResponseDTO> findReservationsByClientId(Long clientId);
}

 

위와 같은 경우, Controller에서 사용하는 응답 구조가 Repository에 노출되기 때문에 심한 결합이 생긴다.

 

뭔가 이해를 한 건지 만 건지 모르겠다... 알 것 같으면서 설명하라고 하면 못 할 것 같다...

Repository에서 DTO 변환을 하는 경우, 컨트롤러에서 사용하는 응답 구조가 Repository에 노출되는 게 무슨 뜻이지? 이게 심한 결합이라 문제가 된다는 게 무슨 뜻인지 이해가 잘 안 갔다.

 

다시 한번 제대로 알아봤다.

 

 

DTO vs Entity

DTO (Data Transfer Object):

  • 클라이언트 요청/응답을 위해 만들어진 프레젠테이션 계층 전용 객체
  • 화면(UI)에 필요한 형태로 구조화됨

Entity:

  • 도메인 모델. DB 테이블 매핑을 위한 비즈니스 핵심 객체

 

응답 구조가 Repository에 노출된다?

이는 예시를 통해 보겠다.

프론트에서 예약 목록을 아래와 같이 받고 싶다고 하자.

[
  {
    "reservationId": 123,
    "designerName": "유재석",
    "reservationDate": "2025-04-25"
  }
]

 

 

잘못된 설계: Repository에서 바로 DTO 반환

public interface ReservationRepository {
    List<ReservationListResponseDTO> findByClientId(Long clientId);
}

 

여기서 ReservationListResponseDTO는 프론트에서 요구한 구조.

근데 이게 Repository에 직접 노출된 상태. 

 

왜 문제인가?

1. Presentation 레이어의 변경이 Persistence 레이어로 전파됨

 

만약 프론트에서 요구가 바뀌어서 reservationId는 빼고, 시간을 보여달라고 한다면?

  1. ReservationListResponseDTO 수정
  2. 이걸 사용하는 Repository 코드도 수정해야 함.

→   위쪽 (Controller/UI)의 요구 변경  →  아래쪽(Repository)까지 영향 

→   이게 강한 결합이다.

2. 관심사 분리가 안 됨

Repository는 DB와의 상호작용만 책임져야 함

DTO는 UI를 위한 데이터 포맷

서로 다른 관심사를 가진 객체가 한 곳에서 뒤섞이면 → 유지보수 어려움

3. Repository를 재사용하기 어려움

나중에 관리자 페이지에서 “예약 목록”을 다르게 보여주려 할 때,

  • 기존 Repository가 ReservationListResponseDTO만 반환하니까
  • 재사용 못 하고 새로 만들어야 함

→ 재사용성↓, 유연성↓

 

결론

Repository가 DTO를 반환하면 

프론트 요구사항이 Repository까지 영향을 미쳐 하위계층까지 연쇄적으로 수정이 필요.

-> 응답 구조가 노출. 결합이 심함.

 

따라서 Repository에서는 Entity 사용하기!