본문 바로가기
개발 방법론

엔티티(Entity)와 값 객체(VO; Value Object)의 차이는 무엇일까요?

by 시니성 2025. 4. 9.

 

도메인 주도 설계(DDD)에서 Entity와 Value Object는 핵심적인 개념들입니다.
이 두 개념은 객체지향 프로그래밍에서 매우 중요하지만, 종종 혼동되거나 잘못 사용되기도 합니다.
이 글에서는 Entity와 VO의 근본적인 차이점과 각각의 개념을 언제, 어떻게 사용해야 하는지 알아보겠습니다.

Entity(엔티티)란?

엔티티는 고유한 식별자(ID)를 가지고 있으며, 그 속성이 변경되어도 동일한 객체로 인식되는 도메인 객체입니다.

주요 특징

  • 식별성(Identity): 고유한 ID로 구별됩니다.
  • 가변성(Mutability): 시간이 지남에 따라 속성이 변할 수 있습니다.
  • 생명주기(Lifecycle): 생성, 변경, 삭제 등의 생명주기를 갖습니다.
  • 동등성 비교: 식별자를 기준으로 동등성을 판단합니다(두 엔티티는 모든 속성이 같아도 ID가 다르면 다른 객체).

엔티티의 예

  • 사용자(User)
  • 주문(Order)
  • 상품(Product)
  • 계정(Account)

VO(Value Object, 값 객체)란?

값 객체는 식별자가 없으며, 객체의 속성 값 자체가 그 정체성을 결정하는 객체입니다.

주요 특징

  • 식별성 없음: 고유한 ID가 없습니다.
  • 불변성(Immutability): 생성 후 속성을 변경할 수 없습니다.
  • 값 자체가 중요: 객체가 가진 값 자체가 의미를 가집니다.
  • 동등성 비교: 모든 속성이 같으면 동일한 객체로 간주됩니다.

값 객체의 예

  • 주소(Address)
  • 금액(Money)
  • 날짜 범위(DateRange)
  • 좌표(Coordinate)
  • 이메일(Email)

Entity와 VO의 핵심 차이점

특성 Entity VO
정체성 ID로 구별됨 값으로 구별됨
가변성 가변적 불변적
동등성 ID가 같으면 동일 모든 속성이 같으면 동일
생명주기 있음 없음(소유 객체에 종속)
핵심 질문 "누구인가?" "무엇인가?"

비유로 이해하기

Entity와 VO의 차이를 쉽게 이해하기 위한 비유를 들어보겠습니다

  • Entity는 사람과 같습니다: 사람은 이름이나 외모가 변해도 같은 사람입니다. 주민등록번호(ID)로 식별됩니다.
  • VO는 돈과 같습니다: 1만원권 지폐는 개별 지폐의 일련번호가 중요한 것이 아니라, 그 가치(1만원)가 중요합니다. 같은 금액의 지폐는 서로 대체 가능합니다.

예시 코드로 알아보기

Entity 예시 (Kotlin)

class User(
    val id: UUID,
    var name: String,
    var email: String
) {
    fun changeName(newName: String) {
        this.name = newName
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as User
        return id == other.id
    }

    override fun hashCode(): Int {
        return id.hashCode()
    }
}

위 코드에서 User 엔티티는 아래와 같은 특성을 갖습니다.

  • 고유한 ID를 가집니다.
  • 이름을 변경할 수 있습니다(changeName 메서드).
  • 동등성 비교(equals)가 ID만으로 이루어집니다.

VO 예시 (Kotlin)

data class Money(
    val amount: BigDecimal,
    val currency: Currency
) {
    fun add(other: Money): Money {
        require(this.currency == other.currency) { "Currency mismatch" }
        return Money(this.amount.add(other.amount), this.currency)
    }

    // data class는 equals와 hashCode를 자동으로 구현합니다.
    // 모든 프로퍼티를 기반으로 동등성을 비교합니다.
}

위 코드에서 Money 값 객체는 아래와 같은 특성을 갖죠.

  • 식별자(ID)가 없습니다.
  • 불변이며, 값을 변경하려면 새 객체를 생성합니다(add 메서드).
  • 모든 속성(amount, currency)이 같으면 동일한 객체로 간주합니다.

실무에서의 적용 방법

Entity를 사용해야 할 때

  • 객체를 추적하고 생명주기를 관리해야 할 때
  • 시간에 따라 상태가 변하는 객체일 때
  • 고유하게 식별해야 하는 객체일 때

VO를 사용해야 할 때

  • 개념적으로 하나의 완전한 값을 표현할 때
  • 불변성이 필요할 때
  • 여러 속성을 묶어 새로운 개념으로 만들 때
  • 수량, 측정값, 설명 등을 표현할 때

결론

Entity와 VO는 도메인 모델링의 기본이 되는 중요한 개념입니다.
이 둘의 핵심적인 차이는 '정체성(Identity)'에 관한 것입니다.
Entity는 고유한 식별자를 통해 "누구인가?"를 중요시하고, VO는 객체의 속성 값을 통해 "무엇인가?"를 중요시합니다.

이 두 개념을 올바르게 이해하고 적용하면 더 명확하고, 유지보수하기 쉬운 도메인 모델을 설계할 수 있습니다.
또한 불필요한 복잡성을 줄이고, 도메인의 의도를 코드에 더 잘 반영할 수 있습니다.

적절한 상황에서 올바른 개념을 선택하는 것이 중요하며, 이는 시스템의 품질과 유연성을 크게 향상시킵니다.

728x90