LALA's blog

DTO 란? 장점은? 본문

개발/우아한테크코스

DTO 란? 장점은?

lala.seeun 2022. 2. 17. 23:45

1단계 자동차 경주 미션을 수행하면서 Layer 간 데이터를 주고받기 위한 DTO를 사용해보았다.

이번에 알게 된 DTO와 관련된 개념들을 정리해보려 한다!

DTO 란?

DTO(Data Transfer Object)로서 계층(Layer) 간 데이터 교환을 위해 사용하는 객체이다.

 

  • 데이터 교환만을 위해 사용하므로 로직을 갖지 않고, getter/setter 메소드만 갖는다.
  • 로직은 없고, 데이터를 담고, 꺼내는 getter/setter 메소드만 담는다.

이런 단순한 개념이면 너무 쉽겠지만..? 우리는 메타인지를 해야하니깐 😙

DTO를 사용했을 때 어떤 장점을 가지고 있는지, 어떻게 사용하는지 알아보도록 하자!

 

 

먼저 DTO를 사용하지 않고 직접 Model 객체를 전달했을 경우를 살펴보자.

// Car.java
public class Car {
   public String name;
   public Type type;
   public int position;
   public Level level;

   // 생성자, getter, setter ...

   public void move(int number) {
      if (number >= 4) {
         position++;
      }
   }
}
// RacingGameController.java
private void showPlayResult() {
   OutputView.printCarInfo(car);
}

위와 같이 Controller 에서 View 에게 Car 객체를 그대로 전달했을 경우 어떤 문제점이 발생할까? 🤔

 

1. Model 의 모든 정보, 상태를 변경할 수 있는 비즈니스 로직들이 View 에 노출된다.

- View 는 정보를 출력해주는 역할이기 때문에 비즈니스 로직을 수행할 필요도, 알 필요도 없다.

- View 에서 경주 결과를 출력하기 위해 필요한 정보는 name 과 position 이다. 필요하지 않은 정보들까지 전달되게 된다.

- 혹은 암호와 같은 중요한 정보가 노출될 가능성이 있다.

 

2. View 에서 Car 객체의 메서드를 호출할 수 있기 때문에 Model 의 상태를 변경시킬 위험이 있다.

- View 에서도 Model 의 객체 상태를 변경했을 경우, 데이터의 일관성이 깨지게 된다.

- Model 의 객체를 그대로 전달했을 경우 얕은 복사(참조)로 인해 원본 데이터가 변경될 위험도 있을 것 같다.

 

3. View <-> Model 간의 결합도가 높아지면서 서로 변경사항이 생길 경우 영향을 끼친다.

- Model 의 구조가 변경되었을 때 View 에서도 변경사항에 맞추어 수정해야 한다.

- View 의 UI 디자인이 변경됐을 경우 이에 맞는 Model 의 데이터 구조도 변경되어야 한다.

- MVC 패턴의 핵심 포인트인 View 와 Model 이 서로 관여하지 않고 본인의 역할에만 집중하면 되는 특징이 적용되지 못한다.

 

 

그럼 DTO 를 사용했을 땐 어떤 점이 다를지 비교해보자!

// CarDto.java
public class CarDto {

   private String name;
   private int position;

   private CarDto(String name, int position) {
      this.name = name;
      this.position = position;
   }

   public String getName() {
      return name;
   }

   public int getPosition() {
      return position;
   }
}
// RacingController.java
private void printRacingRoundResult(AttemptNumber attemptNumber) {
   for (int round = START_ROUND; round <= attemptNumber.value(); round++) {
      List<Car> cars = racingService.findRacingResult(Round.of(round));
      List<CarDto> carDtos = cars.stream().map(Car::toDto)
                              .collect(Collectors.toList());
      OutputView.printRacingInfo(carDtos);
   }
}

 

위에서 발견한 문제점들이 해결된 것을 발견했을 것이다!

1. View 에서는 CarDto 데이터를 받기 때문에 필요한 정보들만 노출되며, Model 의 비즈니스 로직을 알 수 없다. (알 필요도 없다.)

 

2. View 이나 Model 의 변경사항이 발생했을 경우 DTO 를 수정하면 되기 때문에 서로에게 영향을 주지 않는다.

 

3. 계층간 데이터를 전달하는 과정에서 새로운 CarDto 를 갈아 끼워 넣지 않는 이상 데이터가 변조되지 않음을 보장할 수 있다.

 

 

현재 진행하고 있는 자동차 경주 과제에서

View <-> Controleer <-> Service <-> Model 간에 Car 객체의 데이터를 주고받아야 하는 상황이다.

DTO 를 사용했을 경우 위같은 장점들을 발휘할 수 있다고 판단했기 때문에 CarDto 를 추가하여 구현했다!

 

그리고 Car <-> CarDto 로 변환하는 과정을 Service 에서 수행하도록 했는데,

이렇게 구현한 이유도 따로 정리하여 포스팅하도록 해야겠다! 😎

 

 

 

참조