전화번호·금액·우선순위 같은 도메인 개념을 끝까지 문자열이나 숫자로만 다루는 냄새. 같은 검증과 포맷 코드가 여기저기 반복되고, 문자열로 모든 걸 표현하는 "stringly typed" 코드가 된다.
해법은 그 개념만의 작은 타입을 만드는 것이다. 처음에는 값을 감싼 것뿐이라 효과가 작아 보여도, 비교·검증·표시 같은 동작이 생길 때마다 그 자리에 모을 수 있다.
// before
orders.filter(o => o.priority === 'high' || o.priority === 'rush')
// after
class Priority {
static readonly order = ['low', 'normal', 'high', 'rush'] as const
constructor(private readonly value: (typeof Priority.order)[number]) {}
higherThan(other: Priority) {
return Priority.order.indexOf(this.value) > Priority.order.indexOf(other.value)
}
}
orders.filter(o => o.priority.higherThan(new Priority('normal')))- 타입 코드(Type Code)가 동작 분기까지 결정한다면 조건부 로직을 다형성으로 바꾸기으로 이어 간다
- 늘 같이 다니는 원시값 묶음은 데이터 뭉치로 본다
- 불변으로 만들면 값 객체가 된다
- TypeScript에서는 클래스 대신 타입 브랜딩이나 리터럴 유니언으로 가볍게 시작할 수도 있다
출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Replace Primitive with Object · Refactoring.Guru: Primitive Obsession