Entitiy 와 DTO 의 분리

Panda·2022년 2월 22일
4

Spring

목록 보기
9/45

원래는 백엔드 카테고리에 넣을려다가
그냥 Spring 카테고리로 넣게되었다

직면한 문제

프로젝트를 진행하다가 멀티플랫폼 환경에서 개발을 하게 되었는데
공통로직을 작성하는 common 이라는 모듈이 존재한다.

이때 common에서 Request, Response를 위한 Domain(모델)을 작성하는데
문제가 하나 발생을 하였다.

// common/domain/User
@Serializable
data class User(
	val id : Long,
    val name : String,
    val age : Int
)
// backend/domain/User
@Entity
@Data
public class User{
    @Id
    @GeneratedValue
    Long id;
    
    String name;
    
    int age;
}

위에 코드가 존재한다고 할때
저는 처음에 당연히 공통로직에 포함되있는 User를 상속을 하거나 끌어다 써서
JPA를 사용해 DB에 반영을 하려고 했습니다.

하지만 상속을 받자니 각각의 프로퍼티에 어노테이션 처리를 못해줄 뿐만 아니라
필요없는 어노테이션까지 상속이 되는 문제가 생기고

그대로 common에 있는 User를 쓰자니 Entity로 등록이 안되있어 JPA로 관리를 못해주게 되는 문제가 발생하였습니다.

그렇다고 common에 있는 User에 @Entity 처리를 하자니 다른플랫폼에서 사용할때 쓸모없는 기능이 확장이 되어버려 매핑이 안되고....

그래서 구글링을 엄청나게 하다가 발견한 사실인데
위와 같은 상황이 발생한 이유는 바로 제가 DTO랑 Entity랑 동일시 하고있어서 발생한 문제였습니다.

저는 지금까지 당연히 Model을 정의하게 되면 Model이 DTO 역할까지 동시에 하는줄 알았는데
잘못알았던것같습니다.

자 그러면 이런현상을 어떻게 해결해야하고
그 기술이 어떤것인지 한번 공부해보려고 합니다.

Entity 와 DTO의 분리

Entity란?

  • DB 테이블에 존재하는 Column들을 필드로 가지는 객체이다.
  • Entity는 DB의 테이블과 1대 1로 대응되며, 때문에 테이블이 가지지 않는 컬럼을 필드로 가져서는 안된다.
  • 다른 클래스를 상속받거나 인터페이스의 구현체여서는 안된다.

DTO란?

  • Data Transfer Object 의 약자
  • 계층간 데이터 교환 역할
  • Entity를 Controller 같은 클라이언트단과 직접 마주하는 계층에 직접 전달하는 대신 DTO를 사용해 데이터 교환한다.
  • DTO는 그저 계층간 데이터 교환이 이루어 질 수 있도록 하는 객체로, 특별한 로직을 가지지 않는 순수한 데이터 객체여야 한다.
  • DB에서 꺼낸 값을 DTO에서 임의로 조작할 필요가 없기 때문에 DTO에서는 Setter를 만들 필요가 없고 생성자에서 값을 할당한다.

자 이렇게 Entity와 DTO의 정의를 보고 나니까
제가 잘못 이해했단것이 한번더 깨닫게 되었습니다!

둘의 역할부터가 다른데
Entity는 DB 테이블과 1대1로 대응 되는 객체이고
DTO는 계층간 교환을 위해 순수한 데이터 객체입니다.

제가 깨달은것이 바로 관심사의 분리 라고 합니다!!

왜 분리를 해야하는가?

  • 관심사의 분리 : Entity와 DTO를 분리해야 하는 가장 근본적인 이유는 관심사가 서로 다르기 때문이다. 관심사의 분리(separation of concerns, SoC)는 소프트웨어 분야의 오래된 원칙 중 하나로써, 서로 다른 관심사들을 분리하여 변경 가능성을 최소화하고, 유연하며 확장가능한 클린 아키텍처를 구축하도록 도와준다.
    DTO의 핵심 관심사는 이름 그대로 데이터의 전달이다. DTO는 데이터를 담고, 다른 계층 또는 다른 컴포넌트들로 데이터를 넘겨주기 위한 자료구조이다. 그러므로 어떠한 기능 및 동작도 없어야 한다.
    반면에 Entity는 핵심 비지니스 로직을 담는 비지니스 도메인의 영역의 일부이다. 그러므로 Entity 또는 도메인 객체는 그에 따른 비지니스 로직이 추가될 수 있다. Entity 또는 도메인 객체는 다른 계층이나 컴포넌트들 사이에서 전달을 위해 사용되는 객체가 아니다.
    Entity와 DTO는 엄연히 서로 다른 관심사를 가지고 있고, 그렇기 때문에 분리하는 것이 합리적이다.
  • Entity의 값이 변하면 Repository 클래스의 Entity Manager의 flush가 호출될 때 DB에 값이 반영되고, 이는 다른 로직들에도 영향 미친다.
    View와 통신하면서 필연적으로 데이터의 변경이 많은 DTO클래스를 분리해주어야 한다.

  • 도메인 설계가 아무리 잘 되있다 해도 Getter만을 이용해서 원하는 데이터를 표시하기 어려운 경우가 발생할 수 있는데, 이 경우에 Entity와 DTO가 분리되어 있지 않다면 Entity안에 Presentation을 위한 필드나 로직이 추가되게 되어 객체 설계를 망가뜨리게 된다. 때문에 이런 경우에는 분리한 DTO에 Presentation로직 정도를 추가해서 사용하고, Entity에는 추가하지 않아서 도메인 모델링을 깨뜨리지 않는다.

관심사의분리가 가장 중요한 내용인것같아서 자세히 설명을 하였습니다.

해결방안

해결방안은 되게 심플하다.
제가 그냥 Entity와 DTO를 헷갈렸기 때문에 일어난 불참사라서

  • common/domain/User : DTO이기 때문에 Request, Response 처리할때 사용을 해주면 되고
  • backend/domain/User : 실제 DB와 상호작용을 할때는 Entity객체를 사용을 하면 됩니다!

공부하고 나니 제가 바보같이 느껴지네여
가장 기초적인걸 몰랐다니....

그래도 바보같은 삽질로
공통모듈에 대한 공부를 조금이나마 한게 위로가 됩니다.

참고한 사이트

https://velog.io/@syi9595/Entity-DTO%EB%8A%94-%EC%99%9C-%EB%B6%84%EB%A6%AC%ED%95%A0%EA%B9%8C

profile
실력있는 개발자가 되보자!

0개의 댓글