세 가지를 한 문장으로 요약한다면:
- Domain (도메인): 우리 서비스의 핵심 주인공 (예: 회원, 주문). 행동(로직)과 생각(규칙)을 가진 실체.
- DTO (Data Transfer Object): 우체부 또는 택배 상자. 단순히 데이터를 A에서 B로 안전하게 전달하는 역할만 함.
- VO (Value Object): 돈, 주소, 날짜처럼 값 자체가 중요한 개념 덩어리. ‘5,000원’은 그 자체로 의미가 있음.
비유로 이해하기: “카페에서 커피 주문하기”
카페에서 커피를 주문하는 상황에 이 세 가지를 대입해 보겠습니다.
1. Domain (도메인): “손님”과 “바리스타”
- 손님 (Domain Object):
- 데이터: 이름, 멤버십 등급, 보유 포인트
- 행동(로직): “주문한다”, “포인트를 적립한다”, “멤버십 등급이 오른다”
- 손님은 우리 카페 이야기의 핵심 주인공입니다. 손님 없이는 아무 일도 일어나지 않습니다.
- 바리스타 (Domain Object):
- 데이터: 이름, 경력
- 행동(로직): “커피를 만든다”, “재고를 확인한다”
- 바리스타도 이 이야기의 핵심 인물입니다.
2. DTO (Data Transfer Object): “주문서(영수증)”
- 역할: 손님이 키오스크나 포스기에서 주문을 합니다. 이때 손님이 원하는 **데이터(“아이스 아메리카노 1잔, 시럽 추가”)**가 적힌 주문서가 바리스타에게 전달됩니다.
- 특징:
- 단순 데이터 전달: 주문서 자체는 아무런 행동도 하지 않습니다. 그냥 ‘정보’만 담고 있습니다.
- 특정 목적: 이 주문서는 ‘손님 → 바리스타’로 주문 내용을 전달하는 딱 그 목적 하나만 가집니다.
- 선별된 정보: 주문서에는 손님의 모든 정보(나이, 주소 등)가 아니라, 주문에 필요한 정보만 담겨 있습니다.
- “주문 요청 DTO (OrderRequestDto)” 와 같습니다.
- 바리스타가 커피를 다 만들면, “주문하신 아메리카노 나왔습니다”라는 진동벨이나 영수증 번호를 통해 손님에게 알려줍니다.
- 이것은 “주문 완료 응답 DTO (OrderResponseDto)” 와 같습니다.
3. VO (Value Object): “5,000원”이라는 “돈”
- 역할: 손님은 커피 값으로 “5,000원”을 지불합니다.
- 특징:
- 값 자체가 중요: 내가 낸 5,000원 지폐와 다른 사람이 낸 5,000원 지폐는 구분할 필요가 없습니다. 그냥 ‘5,000원’이라는 **값(Value)**이 중요합니다.
- 불변: ‘5,000원’이라는 값은 변하지 않습니다. 5,000원에 1,000원을 더하면 ‘6,000원’이라는 새로운 값이 생길 뿐, 원래의 5,000원이 변하는 게 아닙니다.
- 개념 덩어리: ‘돈’이라는 개념은 “음수일 수 없다”는 규칙을 가집니다. ‘5,000원’이라는 VO는 이 규칙을 스스로 지킬 수 있습니다.
표로 최종 정리
| 구분 | Domain (도메인) | DTO (Data Transfer Object) | VO (Value Object) |
|---|---|---|---|
| 핵심 역할 | 비즈니스의 주인공 (실체) | 데이터 운반용 상자 | 의미를 가진 값 덩어리 |
| 비유 | 사람, 자동차, 주문 | 택배 상자, 신청서, 영수증 | 돈, 주소, 날짜, 색깔 |
| 로직(행동) | ⭕️ 가짐 (가장 중요) | ❌ 가지지 않음 (절대 금지) | ⭕️ 가질 수 있음 (값과 관련된 간단한 로직) |
| 식별 가능? | ID로 구분 가능<br/>(동명이인 ‘홍길동’은 다른 사람) | 구분할 필요 없음<br/>(내용물만 같으면 됨) | 값으로만 구분<br/>(‘5,000원’은 모두 같은 5,000원) |
| 불변성 | 상태가 변할 수 있음 | 보통 불변으로 만듦 | 반드시 불변이어야 함 |
| 주요 목적 | 비즈니스 로직과 규칙을 캡슐화 | 계층 간 데이터 전달 | 원시 타입(int, String)을 의미 있는 객체로 포장 |
| 위치 | domain |
adapter |
domain (도메인의 일부) |
그래서, 왜 구분해야 할까?
- 도메인 vs DTO: 핵심 로직을 보호하기 위해!
- 화면(UI)에 보여줄 데이터 형식이 바뀐다고 해서, 우리 비즈니스의 핵심 주인공인 “손님”의 본질이 바뀌면 안 됩니다. DTO라는 ‘주문서’ 양식만 바꿔주면, “손님”은 안전하게 보호됩니다.
- 도메인 vs VO: 코드를 더 명확하고 안전하게 만들기 위해!
int price라고 쓰는 것보다,Money price라고 쓰는 것이 “이것은 ‘돈’이다”라는 의미를 명확하게 해줍니다.Money객체는 스스로 “음수가 될 수 없다”는 규칙을 지키므로, 개발자가 실수로-1000같은 값을 넣는 것을 원천적으로 막아줍니다.
이 비유와 표를 통해 세 가지 개념의 역할과 차이점이 조금 더 명확하게 다가오셨으면 좋겠습니다. 처음에는 분리하는 것이 번거롭지만, 익숙해지면 훨씬 더 안정적이고 이해하기 쉬운 코드를 작성하실 수 있게 될 겁니다.