백엔드 개발에서 데이터 구조를 정의하고 전달하는 방식은 매우 중요합니다. 특히 VO(Value Object) 와 DTO(Data Transfer Object) 는 자주 사용되는 개념으로, 소프트웨어 아키텍처의 품질과 유지보수성에 큰 영향을 줍니다.
이 문서에서는 VO와 DTO의 기초 개념부터 실무 적용 사례, 그리고 전문가적 관점에서의 활용 방안까지 단계적으로 설명합니다.
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이며, 값이 동일하면
같은 객체로 취급합니다.
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 통신에서 데이터를 담아
전달하는 용도로 사용됩니다.
구분 VO (Value Object) DTO (Data Transfer Object)
목적 도메인 모델의 값 표현 계층 간 데이터 전달 불변성 불변 (Immutable) 가변 (Mutable) 로직 포함 여부 도메인 규칙 포함 가능 로직 없음 비교 기준 값 동등성 주로 참조 비교 사용 위치 도메인 계층 프레젠테이션, API 계층
// Entity → VO 변환
User user = userRepository.findById(1L);
Email email = new Email(user.getEmail());
// VO → DTO 변환
UserDTO dto = new UserDTO(user.getName(), email.getValue());
Address
, Money
, Period
등 복합 값 표현