ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DTO vs VO
    JAVA 2025. 4. 16. 14:13

    실무에서 DTO와 VO를 구분짓지 않고 비슷하게 사용하는 경우가 많다.

    이 둘은 명칭이 다른거처럼 사용하기위한 목적이 엄연히 다르다. 바로 요약부터 하자면 아래와 같다.

    항목 VO (Value Object) DTO (Data Transfer Object)
    목적 값을 표현하는 객체 (불변, 의미 중심) 데이터 전송을 위한 객체 (레이어 간 전달)
    용도 도메인 모델의 구성 요소 계층 간 (예: 컨트롤러 ↔ 서비스) 데이터 전달
    불변성 원칙적으로 불변 (immutable) 변경 가능 (mutable)
    equals/hashCode 값 기준 비교 (필수 구현) 주로 필요 없음
    위치 도메인 모델 내부 계층 사이 (Controller, Service, etc)

    이렇게 봐도 사실 크게 와닿지 않을 수 있다. 추가로 예시코드까지 봐보자.


    이메일에 대한 VO를 예시로 보면

    @Embeddable
    public class Email {
        private String value;
    
        protected Email() {} // JPA 기본 생성자
    
        public Email(String value) {
            if (!value.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
                throw new IllegalArgumentException("Invalid email format");
            }
            this.value = value;
        }
    
        public String getValue() {
            return value;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Email)) return false;
            Email email = (Email) o;
            return Objects.equals(value, email.value);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(value);
        }
    }

    이메일에 대한 validation과 equals, hashCode 함수를 구현해놨다.

    public class UserRequestDto {
        private String email;
        private String password;
        private String name;
    
        // getter/setter
    }

    단순히 요청에대한 값을 담고 get / set 하고 있다.

     

    그럼 여기서 의문점이 하나 생긴다.

    "그럼 DTO에 필드에다가 @NotBlank, @Eamil 등... validation 어노테이션을 사용하면 되는거 아닌가?"

    물론 기능적으로 보면 가능하다고 할 수 있지만 위에서 얘기한바와 같이 vo와 dto는 목적이 다르게 생긴거다. 
    vo는 유효성 검사를 넘어 '도메인 모델링'의 목적이 있다. 더 설명을 보태자면.

     

    1. DTO Validation (@Valid, @Email 등)

    public class CreateUserRequest {
        @NotBlank
        @Email
        private String email;
    
        @NotBlank
        private String name;
    
        // getter/setter
    }

    ✅ 장점

    • 간단하고 빠르게 유효성 검증 적용 가능
    • Spring에서 자동으로 @Valid 처리됨
    • 컨트롤러에서의 잘못된 요청을 쉽게 걸러냄

    ❌ 한계

    • 오직 요청 처리 계층에서만 적용됨 (컨트롤러)
    • 서비스, 도메인 레이어에선 다시 검증하거나 검증 안 한 채 사용될 수 있음
    • 재사용 어려움: 다른 곳에서 같은 규칙을 또 정의해야 함

    🔍 2. VO Validation (생성자에서 검사)

    public class Email {
        private final String value;
    
        public Email(String value) {
            if (!value.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
                throw new IllegalArgumentException("Invalid email format");
            }
            this.value = value;
        }
    
        public String getValue() { return value; }
    }

    ✅ 장점

    • 한 번 생성되면 유효함이 보장된 객체
    • Service, Domain, Entity 어디서든 일관되게 사용 가능
    • 도메인 개념으로써의 의미 전달력이 강력 (String 대신 Email이라는 타입 자체가 의미 있음)
    • 테스트 코드나 다른 계층에서도 재사용성, 안전성 확보

    ❌ 단점

    • 클래스가 많아짐
    • 단순한 프로젝트에선 과할 수 있음

    요약 정리

    VO는 Validation 기능 + 도메인 설계 가치를 동시에 제공하는 도구이다. 단순히 “검증만 되면 된다”는 관점에서 한 발 더 나아가 **“의도를 코드로 표현”**하고 싶은 경우에 VO는 훨씬 유의미합니다.

     

    댓글

#dev-hahm#