[spring] DTO 사용, 변환 위치

김동욱·2023년 10월 14일
0

Spring

목록 보기
2/3
post-thumbnail

1. 들어가기 전

MVC란 소프트웨어 디자인 패턴의 한 종류로서 소프트웨어의 비즈니스 로직(model)과 화면(view)를 구분하는 디자인 패턴입니다. 모델과 뷰는 서로를 인지하지 못하고 Controller가 중간에서 연결을 해줍니다.

view로 들어온 클라이언트의 요청을 Controller가 해석하고 이를 model로 전달하여 작업합니다. 이 과정에서 사용되는 게 DTO(Data Transfer Object)입니다. 즉 세 계층 간의 데이터 교환에 사용되는 java Beans 객체를 의미합니다.

model에서 데이터베이스의 테이블과 매핑하여 데이터를 저장하고 조회하는 등 여러 목적으로 사용되는 객체를 Entity라고 합니다. 예를 들어 회원 정보 테이블이 있다고 가정해 봅시다.(User table)

public class User{

	private Long id;
    private String name;
    private String password;

}

위 테이블의 password 정보는 외부로 유출되면 안되는 정보입니다. 만약 클라이언트의 회원 정보 조회 요청을 이 엔티티로 반환해준다면 어떤 문제가 발생할까요?
아마 원하지 않는 정보까지 모두 반환되게 됩니다.

public ResponseEntity<User> getUser(@PathVariable Long id){
	User user = userService.findById(id);
    return ResponseEntity.ok(user);
  }

이외에도 엔티티 클래스 내부의 비즈니스 로직이 공개될 수 있고, 만약 스키마의 변경이 생길 경우 관련된 모든 로직을 변경해줘야 하기 때문에 유지보수에도 어려움이 생깁니다.

그래서 DTO를 통해 필요한 정보만 반환해주는 거죠

public ResponseEntity<UserDTO> getUser(@PathVariable Long id){
	User user = userService.findById(id);
    return ResponseEntity.ok(UserDTO.from(user));
  }

from메서드는 userDTO에서 user엔티티를 userDTO로 변환해주는 메서드입니다.
오늘은 dto를 공부하면서 엔티티 변환과 dto 변환의 위치와 사용범위에 대해서 알아볼거예요.

public class userDTO{
  private Long id;
  private Long name;
 
  public static userDTO from(User user){
  return userDTO.builer()
  				.id(user.getId());
  				.name(user.getName());
  				.build();
 //빌더 패턴을 사용했지만 다른 방법도 사용가능합니다.
}

1-2. 계층형 아키텍쳐(Layered Architecture)

흔히 사용되는 패턴인 Controller - Service - Repository 구조는 계층형 아키텍처라고 합니다. 애플리케이션을 몇 개의 계층으로 나눠 각 계층이 자신의 역할만 수행할 수있도록 설계한 것 입니다.

  1. Controller 계층은 클라이언트의 요청을 받아 처리하고 응답해줍니다.
  2. Service 계층은 비즈니스 로직을 수행하며 Repository의 데이터 접근을 처리합니다.
  3. Repository 계층은 DB와 연산을 수행하는 계층입니다.

그렇다면 MVC와 계층형 아키텍처는 어떤 관계인걸까요?

계층형 아키텍처는 시스템 내부 동작을 기준으로 구분됩니다.
반면, mvc는 사용자 인터페이스 중심으로 구분되며 service와 repository가 model역할을,
Controller가 요청 응답을 처리하여 view로 반환해줍니다.

2. DTO의 사용범위

그래서 몇 가지 의문이 생기게 됩니다.
dto는 과연 어디서부터 어디까지 사용할 수 있으며, dto와 엔티티를 변환해주는 로직은 어느 위치에 작성되는 것이 좋을까요?

이말은 반대로 생각하면 엔티티를 어느 계층까지 노출시켜도 되느냐로 생각해볼 수 있습니다.
엔티티는 위에서 말했듯 컨트롤러 계층이나 사용자 인터페이스에 노출되면 여러 문제가 생기게 됩니다.
그래서 서비스 계층에서는 엔티티를 통해 여러 비즈니스 로직을 수행하고 이를 컨트롤러로 반환해줄 땐 적절한 dto로 변환해서 반환해줘야 합니다.
서비스 계층에서는 실제 비즈니스 로직을 처리하기 때문에 엔티티로 처리합니다.

물론 상황에 따라 dto를 repository부터 사용해야하는 경우도 생길 수 있지만 이는 그때의 상황에 맞춰 진행해야합니다.

3. DTO의 변환 위치

컨트롤러에 작성해야할까요? 서비스에 작성해야할까요?

컨트롤러 계층에서 dto와 엔티티의 변환을 하는 경우을 먼저 살펴봅시다.
우선 서비스 계층에 dto가 전달되지 않으니 서비스 계층은 오로지 비즈니스 로직에만 집중할 수 있습니다. 그렇기 때문에 재사용에도 용이하고 만일 요청dto가 변경되어도 서비스단은 건드릴 필요가 없죠

하지만 실제로 아주 복잡한 로직이 아닌이상 한 컨트롤러가 서비스를 사용하는 경우가 대부분이라 dto를 서비스까지 넘기고 엔티티로 변환 후 사용하는 경우가 일반적으로 사용됩니다.
이는 서비스 계층이 특정 dto를 직접 사용하므로 결합도가 증가하는 단점이 있습니다.

추가로 그러면 dto 변환 메서드는 어느 곳에 작성될까요??(toEntity, from)
일반적으로 dto 클래스에 작성되지만 이는 dto가 엔티티를 알게 되므로 이 또한 문제가 생기고 반대로 엔티티 클래스에 작성해도 똑같습니다. 그렇다고 별도의 mapper 클래스를 생성하면 추가 클래스 생성이 필요하니 이 또한 완벽한 방법이라고는 할 수 없습니다.

그래서 저는 보통 dto 클래스에 작성하는데 또 공부하다보면 또 다른 구조로 변경될 수도 있겠죠

정리

이처럼 dto와 엔티티의 관계는 프로젝트의 구조와 규모, 팀 규칙에 따라 고려되기 때문에 그때그때 상황에 맞게 대처할 수 있어야 합니다.


https://stackoverflow.com/questions/44096677/spring-mvc-and-three-tier-architecture

profile
안녕하세요. 공부해요

0개의 댓글