thumbnail
VO와 DTO 개념 심층 가이드
Web / Server
2025.09.02.

VO와 DTO 개념 심층 가이드

1. 들어가며

백엔드 개발에서 데이터 구조를 정의하고 전달하는 방식은 매우 중요합니다. 특히 VO(Value Object) 와 DTO(Data Transfer Object) 는 자주 사용되는 개념으로, 소프트웨어 아키텍처의 품질과 유지보수성에 큰 영향을 줍니다.

이 문서에서는 VO와 DTO의 기초 개념부터 실무 적용 사례, 그리고 전문가적 관점에서의 활용 방안까지 단계적으로 설명합니다.


2. VO(Value Object)

2.1 개념

  • 정의: VO는 값을 표현하기 위한 객체로, 특정 도메인의 속성을 불변(Immutable)하게 표현합니다.
  • 특징
    • 동일성(Identity)이 아닌 동등성(Equality) 로 비교합니다.
    • 값이 같으면 같은 객체로 취급합니다.
    • 변경 불가능(Immutable)한 성격을 가집니다.

2.2 예시 (Java)

public class Money {
    private final int amount;
    private final String currency;

    public Money(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public int getAmount() { return amount; }
    public String getCurrency() { return currency; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Money)) return false;
        Money money = (Money) o;
        return amount == money.amount && currency.equals(money.currency);
    }

    @Override
    public int hashCode() {
        return Objects.hash(amount, currency);
    }
}

여기서 Money 객체는 금액과 통화를 나타내는 VO이며, 값이 동일하면 같은 객체로 취급합니다.

2.3 장점

  • 불변성을 통한 안정성 확보
  • 도메인 개념을 코드로 명확하게 표현
  • 값 기반 비교로 직관적인 동등성 판단 가능

3. DTO(Data Transfer Object)

3.1 개념

  • 정의: DTO는 데이터 전송을 위한 객체로, 계층 간 데이터 교환에 사용됩니다.
  • 특징
    • 보통 getter/setter 를 가짐
    • 직렬화/역직렬화에 용이
    • 비즈니스 로직을 포함하지 않음

3.2 예시 (Java)

public class UserDTO {
    private String name;
    private String email;

    public UserDTO() {}

    public UserDTO(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

UserDTO는 컨트롤러와 서비스 계층, 혹은 API 통신에서 데이터를 담아 전달하는 용도로 사용됩니다.

3.3 장점

  • 계층 간 데이터 교환 단순화
  • 네트워크 전송 최적화 (필요한 데이터만 포함 가능)
  • 보안 강화 (민감한 엔티티 정보 노출 방지)

4. VO vs DTO 비교

구분 VO (Value Object) DTO (Data Transfer Object)


목적 도메인 모델의 값 표현 계층 간 데이터 전달 불변성 불변 (Immutable) 가변 (Mutable) 로직 포함 여부 도메인 규칙 포함 가능 로직 없음 비교 기준 값 동등성 주로 참조 비교 사용 위치 도메인 계층 프레젠테이션, API 계층


5. 실무 적용 전략

5.1 언제 VO를 사용할까?

  • 금액, 좌표, 이메일, 전화번호 등 도메인에서 불변성이 필요한 값을 표현할 때
  • 비즈니스 규칙을 캡슐화해야 할 때

5.2 언제 DTO를 사용할까?

  • API 요청/응답에서 데이터 전달 시
  • 외부 시스템 간 데이터 교환 시
  • DB에서 조회한 데이터를 가공하여 반환할 때

5.3 함께 쓰는 방식

  • Entity → VO → DTO 변환 패턴
    • Entity: 데이터베이스의 영속 객체
    • VO: 도메인 로직을 가진 불변 객체
    • DTO: 외부와 데이터를 주고받기 위한 객체
// Entity → VO 변환
User user = userRepository.findById(1L);
Email email = new Email(user.getEmail());

// VO → DTO 변환
UserDTO dto = new UserDTO(user.getName(), email.getValue());

6. 전문가 관점에서의 심화 내용

6.1 VO의 활용 심화

  • DDD(Domain-Driven Design) 에서 핵심 개념
  • 값 객체를 활용해 풍부한 도메인 모델(Rich Domain Model) 을 설계 가능
  • 예: Address, Money, Period 등 복합 값 표현

6.2 DTO의 활용 심화

  • API 최적화: 필요한 데이터만 담아 전송 → 성능 개선
  • MapStruct, ModelMapper 와 같은 매퍼 라이브러리로 자동 변환 가능
  • CQRS(Command Query Responsibility Segregation) 패턴에서 Query DTO 로 자주 사용

6.3 잘못된 사용 시 문제점

  • VO를 단순 데이터 홀더처럼 사용 → 엔티티와 차이 없어짐
  • DTO에 비즈니스 로직 포함 → 유지보수 어려움
  • 계층 간 경계 모호 → 코드 품질 저하

7. 결론

  • VO는 도메인 모델을 풍부하게 하고, 불변성을 보장하며 안정성을 높입니다.
  • DTO는 계층 간 데이터 교환을 단순화하고 보안을 강화합니다.
  • 둘을 적절히 구분하고 조합하여 사용하는 것이 유지보수성과 확장성을 모두 잡는 핵심 전략입니다.

참고 자료

  • Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software
  • Martin Fowler, Patterns of Enterprise Application Architecture
  • Spring Framework 공식 문서
Supabase 심층 가이드
Supabase 심층 가이드
2025.09.03.
Web
Server
트랜드의 트랜드
백엔드에서의 API 통신 선택
백엔드에서의 API 통신 선택
2025.08.29.
Web
Server
API 설계에 대해 정답을 찾아서
🔒 Web Locks API 완벽 가이드: 브라우저 다중 탭 동시성 제어와 리더 선출
🔒 Web Locks API 완벽 가이드: 브라우저 다중 탭 동시성 제어와 리더 선출
2026.10.17.
Web
탭이 10개 열려도 데이터 꼬임 없는 브라우저 락
📡 Broadcast Channel API 완벽 가이드: 브라우저 탭 간 실시간 데이터 동기화
📡 Broadcast Channel API 완벽 가이드: 브라우저 탭 간 실시간 데이터 동기화
2026.10.12.
Web
서버 없이 브라우저 탭끼리 실시간 상태를 동기화하는 가장 간결한 방법

Thank You for Visiting My Blog, Have a Good Day 🌿

© 2024 Developer LIM.