들어가기 전에
본격적인 프로젝트를 들어가기 전에 가장 중요하게 여기고 공부했던 부분이 바로 JPA이다. SpringBoot를 사용하고, 데이터베이스를 사용한다면 JPA를 사용하지 않을 수 없을 것이다. JPA에 관한 개념 및 사용방법은 대수아의 다음 글을 참고하면 된다.
바닥부터 알아보는 Spring Data JPA with MySQL
JPA 에서 가장 중요한 개념 중 하나가 바로 Entity이다. Entity는 정말 편리하지만, 반환 시에는 Dto를 사용하라는 말을 많이 들어보았을 것이다. 처음에는 그 이유를 몰랐는데, 직접 개발을 해보니 정말 맞는 말이었다.
이 글에서는 Entity와 Dto의 개념과, Entity 반환 시 생길 수 있는 문제점, 분리해서 사용해야 하는 이유, Entity와 Dto 변환 위치에 대해 알아볼 것이다.
Entity란?
Entity란, 실제 DB 테이블과 매핑되어 저장되는 객체로, DB 테이블의 컬럼들을 필드로 가진다. DB의 테이블과 1:1 매핑이며, 테이블이 가지지 않은 칼럼을 필드로 가질 수 없다.
Entity는 DB의 영속성을 목적으로 사용되는 객체이기에, 요청이라 응답값을 전달하는 클래스로 사용하는 것은 좋지 않다. 그리고 대부분의 서비스 클래스와 비즈니스 로직들이 Entity 클래스를 기준으로 동작하므로, Entity 클래스가 변하면 많은 클래스에 영향이 간다. 같은 맥락으로, 객체의 일관성과 안정성을 보장하기 위해 setter 메서드의 사용을 지양해야 한다. 그래서 Entity에서는 생성자나 Builder를 사용한다.
생성자를 사용하면, 초기화하는 경우 불변 객체로 활용 가능하고, 이 불변 객체는 데이터 전달 과정에서 데이터가 변조되지 않음을 보장할 수 있다. Builder를 사용하면 멤버 변수가 많아져도 어떤 값을 어떤 필드에 넣는지 바로 확인이 가능하고, 필요한 값만 넣을 수 있다.
Dto란?
Dto란, Data Transfer Object의 약어로 클라이언트와 데이터 전송을 위해 설계된 객체이다.
DAO (Data Access Object) 패턴에서 DB 처리 로직을 숨기고 Dto 라는 결괏값을 내보내는 용도로 사용되었으며, Controller와 같이 클라이언트 단과 직접 마주하는 계층에서는 Dto를 사용해서 데이터를 교환한다. Dto는 getter와 Setter 메서드를 포함하고, 이 외의 비즈니스 로직은 포함하지 않는다.
Entity를 직접 반환 시 생길 수 있는 문제점
- Entity 보안 문제
Entity를 사용자에게 노출하면 테이블 설계를 그대로 노출하는 것이므로 보안상으로 좋지 않다. setter 사용을 권장하지 않는 이유도 Entity 보호를 위해서이다.
- 필요한 데이터만 전송하기 어렵다
테이블에 있는 컬럼 전체를 필드로 가지기 때문에 직접 반환 시 모든 데이터가 반환된다. 이때 불필요한 정보들도 많으므로 트래픽이 증가 해 성능 및 비용면에서 저하가 일어날 수 있다. 사용자가 필요로 하는 데이터만 전송하기 어렵다.
- Entity 구조 변경 시 API 도 수정해야한다.
Entity의 필드 이름이 변경 될 겨우, API 스펙도 추가 변경 해야하므로 효과적인 유지 보수가 어려워진다.
- 순환 참조 문제
Entity 간에 양방향 문제가 발생할 경우, Entity를 반환하는 순간 순환 참조로 인한 무한 JSON 직렬화 이슈가 발생할 수 있다. 다음은 현재 진행중인 프로젝트에서 실제 발생했던 문제이다.
Reservation Entity에 Member가 있고, Member안의 Character Entity에 또 Member가 있어 무한히 순환하고 결국 스택오버플로우가 발생한다.
Dto와 Entity를 분리해야 하는 이유
- MVC 패턴에서 View와 Model을 분리할 수 있다.
Dto는 View와 Controler 간 인터페이스 역할을, Entity는 Model 역할을 한다. 이를 통해 코드의 가독성과 유지보수를 용이하게 할 수 있다.
- 필요한 데이터만 전송 가능
Dto를 만들어 필요한 필요한 필드를 재정의 하여 필요한 데이터만 전송될 수 있다.
- Entity 구조 변경 시에도 안전하다
Entity 구조가 변경되어도 Dto를 사용해 데이터를 전송하면 클라이언트에 직접적으로 영향을 미치지 않으므로, 영향을 최소화 할 수 있다. 서버 간 결합도를 낮추고 유지보수가 용이해진다.
- 순환 참조 예방
Dto는 Entity의 양방향 참조가 포함되지 않는 간단한 구조이므로, 순환 참조가 발생하지 않는다.
- Validation 코드와 Modeling 코드 분리
- Validation 코드 : @NotNull, @NotEmpty, @NotBlank 등
- Modeling 코드 : @Column, @JoinColumn, @ManyToOne, @OneToOne 등
Entity는 DB의 테이블과 매칭되는 필드가 선언되어 있고, 복잡한 비즈니스 로직이 작성되어 있다. 그렇기에 속성에 모델링 코드가 추가되는데, 이때 Validation 코드까지 추가된다면 Entity는 더 복잡해지고 가독성이 저하된다.
이때, 각각 요청마다 다른 Dto를 만들어 상황에 필요한 validation을 추가하면 Entity 클래스에서 모델링과 비즈니스 로직에만 집중할 수 있다.
Dto와 Entity 변환 위치
보통 service 단계에서 Entity와 Dto의 변환이 일어난다. 이 부분에 대해서는 나중에 더 자세히 작성해보도록 하겠다.
마치며
처음에는 귀찮아서 Dto를 분리하지 않고 싶었지만, 하다보니 분리하지 않을 수가 없었다는 것을 깨닫고 그럴거면 확실하게 알고 가자 해서 작성해보았다. 앞으로 같은 실수는 하지 않을 것 같다.
참고
https://wildeveloperetrain.tistory.com/101
https://hstory0208.tistory.com/entry/SpirngJPA-Dto와-Entity를-분리해서-사용하는-이유
'TroubleShooting' 카테고리의 다른 글
React Too many re-renders에서 벗어나기 [ ps.스터디 장께... 업데이트했어요.. no 날먹. ] (0) | 2024.08.18 |
---|