노트

값 객체

Value Object

설계#architecture · 연결된 개념 8개

쉽게 말하면

값 객체는 지폐와 같아요. 내 만 원과 친구의 만 원은 서로 바꿔도 똑같고, 액수를 바꾸고 싶으면 지폐에 덧칠하는 대신 다른 지폐로 통째로 바꿔요. 그래서 남에게 건네도 몰래 바뀔 걱정이 없어요.

비유가 깨지는 곳 모든 걸 값으로 다루면 안 돼요. 고객처럼 여러 곳이 같은 대상을 공유하고 바뀌면 모두 알아야 한다면, 복제한 값 대신 같은 인스턴스를 가리키는 참조로 다뤄야 일관성이 지켜져요.

식별자 없이 담고 있는 값 자체로 같음을 판단하는 불변 객체. 금액, 기간, 주소, 이메일처럼 "어떤 것"이 아니라 "얼마·무엇"을 나타내는 개념에 쓴다. 식별자로 같음을 판단하고 상태가 바뀌는 엔티티(Entity)와 대비된다(도메인 주도 설계 (DDD)).

  • 바꿀 수 없으므로, 바꾸려면 새 객체를 만들어 통째로 교체한다
  • 같은 값이면 같은 객체로 본다. 언어가 기본으로 참조 비교를 한다면 동치 비교 메서드를 직접 둔다
  • 밖으로 건네도 몰래 바뀔 걱정이 없어 동시성·분산 환경에서 특히 다루기 편하다
class Money {
  constructor(readonly amount: number, readonly currency: string) {}
  minus(n: number) { return new Money(this.amount - n, this.currency) }
  equals(o: Money) { return this.amount === o.amount && this.currency === o.currency }
}
product.price = product.price.minus(1000) // 내부 값을 고치지 않고 교체

참조로 다뤄야 할 때

여러 객체가 한 대상을 공유하고, 그 대상이 바뀌면 모두가 알아야 한다면 값이 아니라 참조여야 한다. 같은 고객 데이터를 주문마다 복제해 두면 갱신할 때 하나라도 놓치면 일관성이 깨진다. 이럴 때는 저장소에서 같은 인스턴스를 꺼내 쓰게 바꾼다(값을 참조로 바꾸기, Change Value to Reference). 반대로 공유가 필요 없는 내부 객체는 값으로 바꾼다(참조를 값으로 바꾸기, Change Reference to Value).

출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Change Reference to Value · refactoring.com: Change Value to Reference · Martin Fowler: Value Object

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 특이 케이스와 널 객체

    특정 값(가장 흔하게는 null이나 "미확인" 같은 표시값)을 만날 때마다 같은 처리를 하는 코드가 곳곳에 흩어져 있을 때, 그 경우를 대표하는 객체를 하나 만들어 공통 동작을 담는 패턴. null을 대표하면 널 객체(Null Object)라 부르며, 널 객체는 특이 케이스(Special Case)의 한 예다.

  • 가변 기본 인자 함정

    파이썬 함수의 기본값은 함수를 정의할 때 한 번 평가되어 그 객체가 계속 재사용된다. 그래서 리스트·딕셔너리 같은 변경 가능한 객체를 기본값으로 쓰면, 호출할 때마다 같은 객체가 공유되어 값이 쌓인다.

  • 임시 변수를 질의 함수로 바꾸기

    계산 결과를 담아 두던 임시 변수를 그 값을 돌려주는 함수로 바꾸는 리팩터링. 긴 함수를 쪼개기 전 단계로 특히 쓸모 있다.

  • 구조와 동작, 옵션의 가치

    켄트 벡이 정리 시점을 판단하려고 꺼내는 경제학 틀. 소프트웨어는 두 가지 가치를 만든다. 오늘 하는 일(동작)과, 내일 새로 할 수 있게 되는 일(옵션)이다. 구조는 동작을 바꾸지 않지만 옵션을 만든다.

  • 매핑된 타입과 keyof

    매핑된 타입(Mapped Types)은 기존 타입의 키를 하나씩 돌며 새 타입을 만드는 문법([K in keyof T]: …)이다. keyof T는 객체 타입의 키 유니언을, T[K](인덱스 접근 타입, Indexed Access Type)는 그 키의 값 타입을 꺼낸다.

보기 옵션