DTO, Command Object, Value Object #1

Su hwan Choi·2022년 11월 14일
0

시작하며

DTO, Command Object, Value Object (이하 VO)에 대해 적어보려 한다.
특히 DTOVO 가 구분없이 불리게된 이유를 찾아봤다
DTO 라는 개념 자체가 긴 시간을 거쳐, 여러 환경에서 사용하다보니 그 과정을 정리해둔 페이지는 아직 보지 못한것 같다.
DTO에 대해 좀더 자세히 알게 된다고해서 개발능력이 혁신적으로 올라가지는 않겠지만, 앞으로 DTO 에 관련된 결정을 내릴때 도움이 될 것이라 생각한다.

1. 데이터 전달이 목적


DTO의 최초정의는 특정한 객체를 가리키는게 아니라. 패턴의 이름이다.
데이터를 좀더 쉽게 전달하는것이 이 패턴의 목적이다.
간단한 프로젝트를 통해 예를 들어보자면

@PostMapping("/new")
public ResponseEntity<Long> create(@RequestBody Map<String, String> parameters)
{
    Address address = Address.builder()
            .city(parameters.get("city"))
            .street(parameters.get("street"))
            .zipcode(parameters.get("zipcode"))
            .build();

    Member member = Member.build(
            parameters.get("name"), address);
    return ResponseEntity.ok(memberService.join(member));
}

DTO가 적용되지 않은 코드를

@PostMapping("/new")
public ResponseEntity<Long> create(@RequestBody @Valid MemberForm form)
{

    Address address = Address.builder()
            .city(form.getCity())
            .street(form.getStreet())
            .zipcode(form.getZipcode())
            .build();

    Member member = Member.build(form.getName(), address);
    return ResponseEntity.ok(memberService.join(member));

}
public class MemberForm
{
    @NotEmpty
    private String name;
    private String city;
    private String street;
    private String zipcode;
	  //getter setter
}

위와 같은 형태로 바꿀때 MemberFormDTO 패턴이 적용된 객체라 할 수 있고, 이를 줄여서 우리는 보통 DTO, DTO 객체 라고 부른다.

데이터 전달의 주의점


DTO 는 단순한 구조여야 한다.
데이터 전달을 목적으로 만들어졌기 때문에 다른 목적이 있어서는 안된다.
여기서 다른목적에는 DTO 자신을 생성하는 것도 포함된다.
예를 들어 위의 프로젝트에서 회원목록을 노출하는 API 의 결과를 전달한다고 할때

@Entity
public class Member
{
    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;
	  //getter, setter
...
}

위의 Member.java 를 직접 전달하면 안된다

이유를 적어보자면 우선 DTO 패턴을 처음 제시한 마틴 파울러의 말에 따르면
직렬화를 지원해야 하기 때문이다.
위와같은 도메인객체는 다른 객체와 연결망이 매우 많아서 직렬화가 어렵거나 복잡하다.
데이터를 사용하는 쪽에서 다시 요청을 하지 않을 만큼의 정보를 모아 하나의 객체로 만들어서 보내는것이 DTO패턴이라 할 수 있다.

public class MembersResponse
{
    private long id;
    private String name;
    private String city;
    private String street;
    private String zipcode;
}

DTO와 재사용

DTO의 재사용 여부에는 정답은 없고, 개발이 진행되는 과정을 보고 정해야 한다.
만약 여러개의 API 에서 사용하는 데이터가 같은경우 DTO를 하나만 만들어서 재사용 하는것이 좋을까?

재사용하지 않을경우 가장 눈에 띄는 문제는 DTO 객체가 너무 많아지는 것이다.
그래서 간혹 처음 개발을 할때 다른 API 더라도 데이터가 같다면 공통DTO를 만들고 개발을 시작하는 경우가 있는데
이것보다는 처음에는 별개의 DTO로 시작을 하되 개발하는 도중 합쳐도 된다고 판단이 되는경우가 됬을때 합치는 것을 추천한다.
경험상 눈에 보이는 별개의 클래스를 합치는 작업과 하나로 합쳐진 클래스를 눈에 보이는 여러개의 클래스로 나누는 작업중에
전자의 작업이 훨씬 처리하기 쉬웠다.
즉 미래의 사건을 예측해서 먼저 적용하지 말고, 적용할 수 있는 구조로 만들어두는것 이 좋다고 생각한다.

DTOVO


VO값 객체 를 말한다.
객체지향 시스템에서 참조객체 와 구분되는 개념이다. 값객체는 식별자가 없는 말 그대로 값을 의미한다.
가령 회원정보 라는 개념이 있을때 회원정보를 구성하는 회원의 주소는 값객체 라고 볼 수 있다.
간혹 VODTO와 혼용하는 경우가 있는데 이 것은 J2EE 에서 데이터전달에 사용되는 객체값객체 를 사용하면서 발생했다.
이후 J2EE에서는 transfer object 라는 용어로 변경했다.

다른객체가 참조하는데서 사용되기 때문에 읽기전용인 객체여야 한다.

DTOCommand Object


Command Object작업을 캡슐화 하는 것이 목적이다.
Command ObjectCommand Pattern의 용어다.

토비의스프링@ModelAttribute관련된 내용에 다음과 같이 나와있다.


도메인 오브젝트나 DTO의 프로퍼티에 요청 파라미터를 바인딩해서 한 번에 받으면 @ModelAttribute 라고 볼 수 있다. 하나의 오브젝트에 클라이언트의 요청정보를 담아서 한 번에 전달되는 것이기 때문에 이를 커맨드 패턴에서 말하는 커맨드 오브젝트라고 부르기도 한다.
토비의 스프링 3.1Vol2 p492

사용자가 하는 작업을 Command 라고 봤을때, 이 작업에 필요한 정보들을 한번에 전달하는 의미로 본다면 Command Object 라고 볼 수있다.
그래서 @ModelAttribute를 설명하는 과정에서 등장한 것이다.

spring-mvchtml-form 을 사용한 환경에서는 적합하지만, REST API 로 세분화된 환경에서는 외부와 통신하는 객체에 Command Object라는 명칭은 적합하지 않다고 본다.

실제로 Spring javadoc 에서도 3.0이전까지는 Command class라는 개념이 등장한다.

마무리

어찌보면 간단한 내용이라 할 수 있는 DTO, VO, Command Object 는 비슷한 의미지만 용어가 등장한 배경이 조금씩 다르다.
간혹 개발을 하다보면 이건 DTO인가? VO인가? 라는 질문을 받는데,

DTO는 데이터전달을 위해 등장한개념
VO는 객체지향 설계에서 을 표현하기 위해 등장한 개념

어찌보면 이 질문은 성립할 수 없는 질문이라 생각한다.
애초에 둘중 하나를 선택할 수 있는 같은 관점이 아니기 때문에 위 개념을 이해하면 헷갈리는 일은 없을것 같다.
추가로 DTO생성을 담당하는 역할과, 의존관계와 관련된 DTO의 역할에 관해서는 다른 글에서 써보겠다.

0개의 댓글