노트

기본형 집착

Primitive Obsession

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

쉽게 말하면

기본형 집착은 금액, 전화번호, 우선순위를 끝까지 맨 숫자나 글자로만 다루는 거예요. 그러면 '올바른 전화번호인가' 같은 확인을 쓸 때마다 반복하게 되니, 그 개념만의 작은 타입을 만들어 한곳에 모아요.

비유가 깨지는 곳 처음엔 값을 감싸기만 해서 효과가 작아 보여요. 진짜 이득은 비교·검증·표시 같은 동작이 생길 때마다 그 타입에 모이는 데서 나오고, TypeScript에선 타입 브랜딩으로 가볍게 시작할 수도 있어요.

전화번호·금액·우선순위 같은 도메인 개념을 끝까지 문자열이나 숫자로만 다루는 냄새. 같은 검증과 포맷 코드가 여기저기 반복되고, 문자열로 모든 걸 표현하는 "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')))

출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Replace Primitive with Object · Refactoring.Guru: Primitive Obsession

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 매핑된 타입과 keyof

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

  • TypeScript 개요

    TypeScript는 JavaScript에 정적 타입(Static Typing)을 더한 슈퍼셋(superset) 언어다. 브라우저는 TS를 그대로 실행하지 못하므로, 타입을 검사한 뒤 타입 표기를 지운 JavaScript로 컴파일된다. 타입 표기는 프로그램의 런타임 동작을 바꾸지 않는다.

  • 보호 구문

    정상 흐름이 아닌 경우를 함수 앞부분에서 검사하고 바로 빠져나오는 조건문. 중첩된 if-else를 평평하게 펴서 핵심 흐름을 드러낸다.

  • 템플릿 리터럴 타입

    템플릿 리터럴 타입(Template Literal Types)은 문자열 리터럴 타입을 템플릿 문자열 문법으로 조합해 새 문자열 유니언을 만드는 기능이다. 유니언을 넣으면 가능한 모든 조합이 나온다.

  • 타입 좁히기와 타입 가드

    타입 좁히기(Narrowing)는 선언된 넓은 타입(유니언, unknown)을 실행 경로를 따라 더 구체적인 타입으로 줄여 가는 과정이다. 그 근거가 되는 런타임 검사를 타입 가드(Type Guard)라고 한다.

보기 옵션