To Dare Is To Do!
DTO와 Entity의 변환 본문
지난번 DTO와 Entity에 대해서 작성한 글에서 DTO는 레이어 간 객체 전송을 Entity는 DB 테이블 매핑을 위한 객체라고 확인한 적이 있다.
https://whitehartlane.tistory.com/11
그렇다면 클라이언트에서 데이터를 DTO에 받아 전송하다 DB에 가기 전에는 Entity로 변환해야 하는데 어디서 해야 하는 것일까? 또 어떠한 방법으로 변환해 주어야 하는 것일까?
이번 글을 쓰면서 한번 생각해 보자!
DTO <ㅡ> Entity 변환 계층
어느 계층에서 DTO와 Entity를 변환해주는 것이 적절할까?
Controller에서 변환?
Controller 계층은 클라이언트의 요청을 처리하고 사용자 인터페이스와 비즈니스 로직을 분리한다.
만약 DTO와 Entity의 변환이 Controller 계층에서 발생한다면 변환 과정에서의 비즈니스 로직이 Controller 계층에서 처리된다는 것을 의미한다.
이는 아키텍처 구조를 위반하며 Controller 계층이 여러 Service의 객체를 의존하게 되어 유지 및 보수에 어려움을 겪을 수 있다.
ex) 복잡한 어플리케이션의 경우 Controller가 View로부터 전달받은 DTO만으로 Entity를 구성하기 힘들기 때문에 여러 Service 혹은 Repository에 의존하게 된다.
또한 View에 반환할 필요가 없는 데이터까지 Controller까지 넘어올 수 있다.
Service에서 변환한다면?
하지만 비즈니스 로직을 관리하는 Service 계층에서 DTO와 Entity 간 변환 작업을 수행한다면 아키텍처 구조를 지키면서 View 화면까지 모든 데이터가 노출되는 것을 방지할 수 있다.
또한 Service에서 변환작업을 수행해두면 여러 Controller 메소드에서 동일한 변환 작업을 여러 번 수행할 필요도 없어진다.
이렇게 보면 Service 계층에서 변환 작업을 수행하는 것이 정답처럼 보인다.
하지만 Service 계층이 모든 변환 작업을 떠안으면 Service 계층의 복잡도는 증가하는 등 단점 또한 존재한다는 것을 인지해야 한다.
그렇다면 Repository??
Repository는 데이터베이스와 상호작용하는 계층이다. Entity를 통해 DB와 상호작용하는 계층에서 비즈니스 로직이 포함된 DTO를 사용한다면 아키텍처 구조를 위반할 수 있다.
또한 Repository는 Entity의 영속성을 관리하는 곳으로 다른 계층에서 변환 작업을 수행하는 것이 코드의 명확성과 유지보수성을 높일 수 있다.
그럼 어디에서??
정답은 없다. 각 계층에서의 변환은 장단점이 있기 때문에 상황에 맞는 계층에서 변환 작업을 수행해야 한다.
아직은 어렵다.. 앞으로 마주하는 예시들은 어떻게 적용되었는지 꾸준히 공부하면서 나의 기준을 명확하게 만들어 나가야겠지만 일단 Service 계층에서 변환 작업을 수행해야겠다.
변환 방법
DTO와 Entity의 변환 방법에는 여러 가지가 있다.
간단하게는 Setter를 활용할 수 있지만 사용 의도를 명확하게 파악하기 어렵거나 값의 일관성을 유지하기 힘들다는 이유로 지양해야 한다는 의견이 많다.
그럼 어떠한 방법을 쓸까?
바로 @Builder (빌더 패턴)이다.
빌더패턴을 추천하는 이유를 살펴보면
- 필요한 데이터만 설정 할 수 있다.
- 유연성을 확보할 수 있다.
- 코드의 가독성을 높여준다.
- 불변성을 확보할 수 있다.
등이 있다.
lombok을 활용한다면 사용 방법도 간단하다!
빌더 패턴을 적용할 객체에 @Builder 어노테이션을 달아주면 각 필드를 설정하는 메서드와 객체를 생성하는 build 메서드가 있는 빌더 클래스가 된다.
@Data
@Builder
public class FoodDTO {
private String name;
private Integer price;
private String description;
private String belong;
}
@Data
@Builder
@Entity
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private Integer price;
private String description;
private String belong;
}
// DTO를 Entity로 변환하는 메서드
public Food toEntity() {
return Food.builder()
.name(this.name)
.price(this.price)
.description(this.description)
.belong(this.belong)
.build();
}
// Entity를 DTO로 변환하는 메서드
public static FoodDTO fromEntity(Food entity) {
return FoodDTO.builder()
.name(entity.getName())
.price(entity.getPrice())
.description(entity.getDescription())
.belong(entity.getBelong())
.build();
}
참고
https://tecoble.techcourse.co.kr/post/2021-04-25-dto-layer-scope/
https://dodop-blog.tistory.com/265
'Spring' 카테고리의 다른 글
객체 지향 설계의 5가지 원칙(SOLID) (1) | 2023.12.23 |
---|---|
DTO vs VO vs Entity (0) | 2023.11.07 |
HTTP Method (1) | 2023.11.06 |
Spring 3계층 속 DI (0) | 2023.11.05 |
직접 만들고 뜯어본 Controller (1) | 2023.11.03 |