핵심 인사이트 (3줄 요약)

  1. 본질: 엔티티 (Entity)는 고유 식별자(ID)로 구별되는 도메인 객체로 시간이 지나도 동일성이 유지되는 반면, 값 객체 (Value Object)는 식별자 없이 속성 값 전체로 동일성이 결정되는 불변(Immutable) 도메인 개념으로, 복사·비교·교체가 자유롭다.
  2. 가치: 엔티티와 값 객체를 올바르게 구분하면 도메인 모델의 명확성이 높아지고, 값 객체의 불변성 덕분에 동시성 버그·복사 오류가 예방되며, 도메인 개념이 코드에 정확히 표현된다.
  3. 판단 포인트: 판단 기준은 '이 객체가 시간이 지나도 추적되어야 하는가?'다. 추적이 필요하면 엔티티(ID 부여), 추적 없이 값 자체가 의미를 가지면 값 객체(불변)로 설계한다.

Ⅰ. 개요 및 필요성

DDD에서 도메인 객체는 크게 엔티티와 값 객체로 분류된다. 이 구분은 비즈니스 도메인을 정확히 모델링하는 데 핵심적이다.

엔티티의 예: '주문 #1001'은 주문 내용이 바뀌어도(항목 추가, 상태 변경) 여전히 '주문 #1001'이다. 반면 '₩10,000'은 어디서 왔든 같은 금액이면 동일한 값 객체다. 같은 금액의 서로 다른 지폐를 구별할 필요가 없듯이.

┌─────────────────────────────────────────────────────────────┐
│          엔티티 vs 값 객체 비교                               │
├─────────────────────────────────────────────────────────────┤
│  엔티티 (Entity)                값 객체 (Value Object)       │
│  ─────────────────              ───────────────────────      │
│  고유 ID 존재                   ID 없음                      │
│  가변 (Mutable)                 불변 (Immutable)             │
│  참조 동일성 비교               값 동일성 비교               │
│  생명주기 추적                  교체 가능                    │
│                                                             │
│  예: Order(orderId)             예: Money(amount, currency)  │
│      User(userId)                   Address(city, street)   │
└─────────────────────────────────────────────────────────────┘
  • 📢 섹션 요약 비유: 사람(엔티티)은 이름이 바뀌어도 주민등록번호(ID)로 동일인이 확인된다. 반면 1만원 지폐(값 객체)는 어느 지폐든 1만원이면 동일하다.

Ⅱ. 아키텍처 및 핵심 원리

값 객체의 가장 중요한 특성은 불변성(Immutability)이다. 값 객체를 수정하는 대신 새 값 객체를 생성하여 교체한다. 불변성으로 인해 Thread-safe하고 공유가 안전하다.

항목설명포인트
동일성 기준고유 ID모든 속성 값
가변성가변(속성 변경 가능)불변(교체만 가능)
생명주기추적(영속화·조회 필요)추적 불필요
비교 방식ID 비교속성 전체 비교
공유 가능성위험(참조 공유 시 부작용)안전(불변이므로 공유 OK)
┌─────────────────────────────────────────────────────────────┐
│           값 객체 불변성 - 교체(Replace) 패턴               │
├─────────────────────────────────────────────────────────────┤
│  // 잘못된 방법 (가변 값 객체 - 버그 위험)                  │
│  price.setAmount(12000); // 기존 객체 수정                  │
│                                                             │
│  // 올바른 방법 (불변 값 객체 - 교체)                       │
│  Money newPrice = new Money(12000, "KRW");                  │
│  order.changePrice(newPrice); // 새 객체로 교체             │
└─────────────────────────────────────────────────────────────┘
  • 📢 섹션 요약 비유: 값 객체는 수표(Check)처럼 금액이 적혀 있으면(속성값) 어느 수표든 같다. 찢어지면 같은 금액의 새 수표(새 객체)를 발행하면 된다.

Ⅲ. 비교 및 연결

엔티티와 값 객체를 혼동하는 가장 흔한 실수는 'Address'를 엔티티로 설계하는 것이다. 주소는 주민번호가 없으므로 값 객체로 설계해야 하며, 주소 변경 시 주소 객체를 수정하지 않고 새 Address 값 객체로 교체한다.

비교 축AB
적합한 경우고유 추적 필요 (Order, User)불변 개념 (Money, Address)
부적합한 경우속성값으로 충분한 개념생명주기 추적이 필요한 개념
대표 예시Order, User, ProductMoney, Address, DateRange
  • 📢 섹션 요약 비유: 도메인 개념이 엔티티인지 값 객체인지 불분명하면 비즈니스 전문가에게 '이것을 ID로 추적해야 합니까?'라고 질문한다.

Ⅳ. 실무 적용 및 기술사 판단

엔티티는 여권(ID 추적)처럼, 값 객체는 동전(속성값으로 동일성 결정)처럼 설계한다. 여권은 유효기간이 바뀌어도 동일 인물의 여권이지만, 동전은 동일 금액이면 모두 같다.

판단 체크리스트

  1. 식별자(ID)가 필요한 도메인 개념은 엔티티로, 속성값이 동일성을 결정하는 개념은 값 객체로 설계되어 있는가?
  2. 값 객체가 불변(Immutable)으로 구현되어 있으며 수정 시 새 객체로 교체하는가?
  3. Money, Address, DateRange 등 도메인 개념이 원시 타입(int, String) 대신 값 객체로 표현되어 있는가?
  4. 엔티티 간 참조가 직접 객체 참조 대신 ID 참조로 이루어지는가?
  5. 값 객체가 에그리게이트 내에서만 사용되고 에그리게이트 루트를 통해 접근되는가?
  • 📢 섹션 요약 비유: 엔티티는 여권(ID 추적)처럼, 값 객체는 동전(속성값으로 동일성 결정)처럼 설계한다.

Ⅴ. 기대효과 및 결론

엔티티·값 객체 구분으로 도메인 모델의 의도가 코드에 명확히 표현되고, 불변 값 객체 덕분에 동시성 버그와 복사 부작용이 예방된다. 값 객체를 통한 Primitive Obsession(원시 타입 남용) 해소로 타입 안전성도 향상된다.

한계는 값 객체 설계 시 불변성 구현 비용과, 일부 ORM(JPA 등)에서 값 객체 영속화가 복잡할 수 있다는 점이다. 함수형 프로그래밍의 불변 자료구조와 값 객체의 융합이 미래 방향이다.

  • 📢 섹션 요약 비유: 엔티티는 이름이 바뀌어도 동일인 취급(ID 추적), 값 객체는 같은 금액이면 동일 취급(속성값 비교). 이 두 가지 구분이 도메인 모델의 핵심이다.

📌 관련 개념 맵

[DDD 엔티티·값 객체] → [에그리게이트 설계] → [불변 Value Object] → [CQRS 읽기 모델 최적화]

개념연결 포인트
에그리게이트 루트엔티티를 포함하는 일관성 경계
유비쿼터스 언어엔티티·값 객체의 이름 기준
리포지토리엔티티(에그리게이트 루트)를 영속화
Domain Primitive비즈니스 규칙을 포함한 값 객체 패턴

📈 관련 키워드 및 발전 흐름도

[프리미티브 타입 남용] → [값 객체·엔티티 구분(Evans)] → [불변 Value Object] → [Domain Primitive 패턴] → [함수형 불변 자료구조 융합]

👶 어린이를 위한 3줄 비유 설명

  1. 엔티티는 사람처럼 이름이 바뀌어도 주민번호로 구별해요.
  2. 값 객체는 동전처럼 금액이 같으면 어느 동전이든 똑같아요.
  3. 이 두 가지를 잘 구분하면 코드가 훨씬 명확해져요!