본문 바로가기
Java

<JAVA> DTO가 뭐예요? 꼭 써야 하나요?

by 돈민찌 2021. 11. 8.
반응형

서비스가 요청을 처리하고 클라이언트에게 리턴할 때 처리한 모델 자체를 리턴하는 경우는 거의 없다. 보통은 데이터를 전달하는 데에 사용하는 오브젝트인 DTO(Data Transfer Object)로 변환해 리턴한다. 왜 귀찮게 이런 작업을 하는 것일까?

첫번째 이유 비즈니스로직의 캡슐화

ORM/JPA를 사용할 때 모델 하나하나는 데이터베이스의 테이블 구조와 매우 유사하다. 모델이 갖고 있는 필드들은 테이블의 스키마와 비슷한 확룰이 높다. 대부분의 비즈니스는 외부인이 자사의 데이터베이스의 스키마 형태를 아는 것을 원하지 않는다. 이때, DTO처럼 다른 오브젝트로 바꿔 반환하면 외부 사용자에게 서비스 내부의 로직, 데이터베이스의 구조 등을 숨길 수 있다. (방법: 멤버 변수는 private로 두고, public한 getter,setter를 만들어준다.)

두번째 이유 클라이언트에게 필요한 정보를 모델이 전부 담을 수 없는 경우

가장 대표적으로 에러메세지가 있다. 만약 서비스 실행 도중 사용자 측에 에러가 발생하면 이 에러메세지를 어디에 포함해야 하는가? 모델은 서비스 로직과는 관련이 없기 때문에 모델에 에러메세지를 담기는 애매하다. 이런 경우 DTO에 에러 메세지 필드를 선언하고 DTO에 포함시키면 된다.

DTO를 사용해야 할 상황은 사실 많다. 위에서 예를 든 상황을 제하면, 예를 들어 새로운 new Object가 선언될 때마다 새로운 UUID가 생성된다면? 혹은 전체 객체의 수를 카운트하고 있는 글로벌 변수가 있다면? 그렇다면 정식으로 객체로 생성되기 전까지 데이터가 전송되는 동안에는 객체를 생성해서는 안된다. 대신 객체의 생성에 필요한 정보를 담을 DTO를 생성해서 주고받거나 이동, 저장하는 방법이 있을 것이다. 

데이터 전송 개체 설계 패턴은 전송을 위해 데이터를 집계하고 캡슐화하는 개체를 사용하는 엔터프라이즈 애플리케이션 아키텍처 패턴 중 하나입니다. 데이터 전송 개체는 본질적으로 데이터 구조와 같습니다. 비즈니스 로직을 포함하지 않고 직렬화 및 역직렬화 메커니즘을 포함해야 합니다. StackAbuse.com, Victoria Seuik

예시)

// Course.java

@Getter
@NoArgsConstructor
@Entity
public class Course extends Timestamped {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String tutor;

    public Course(String title, String tutor) {
        this.title = title;
        this.tutor = tutor;
    }

    public void update(CourseRequestDto requestDto) {
        this.title = requestDto.getTitle();
        this.tutor = requestDto.getTutor();
    }
}
// CourseService.java

@RequiredArgsConstructor
@Service
public class CourseService {
    private final CourseRepository courseRepository;

    @Transactional
    public Long update(Long id, CourseRequestDto requestDto) {
        Course course1 = courseRepository.findById(id).orElseThrow(
                () -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
        );
        course1.update(requestDto);
        return course1.getId();
    }
}

DTO에 어플리케이션의 비즈니스로직이 드러나서는 안된다! => 직렬화된 데이터를 확인한다 해서 내부의 로직까지 파악 가능한 상태라면 상당히 취약한 어플리케이션이 될 것이다.

But, HOW?

직렬화(Serialization): 객체(Object) 를 전송(저장) 가능한 형태로 만드는 것! 예) JSON.stringify(Object) => json
(마샬링 Marshaling이라고 부르기도 한다. 컴퓨터 과학에서 한 객체의 메모리에서의 표현 방식을 저장 또는 전송에 적합한 다른 데이터 형식으로 변환하는 과정. 한 컴퓨터에서 데이터를 저장할 때, 다른 프로그램으로 전송할 때, 다른 컴퓨터로 전송할 때 모두 포함. 출처 링크 참조)
역직렬화(Deserialization): 직렬화된 파일을 다시 객체의 형태로 만드는 것! 예) JSON.parse(json) => Object

제법 잘 만든것 같쥬?

반응형

댓글