본문 바로가기
C.W.K.
Stream
Lesson 02 of 05 · published

타입으로 생각하기: 구현 전에 가능한 세계 그리기

~10 min · ts-epilogue, philosophy, thought-shape

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"타입은 완성된 JavaScript 위에 붙이는 영수증이 아니라, 만들 시스템의 가능한 세계를 먼저 그리는 도구야."

주석에서 설계 표면으로

처음에는 TypeScript를 'JavaScript에 타입 주석을 더한 것'으로 느끼기 쉬워. 익숙해지면 질문의 순서가 바뀐다. 어떤 데이터가 들어오고, 어떤 상태가 가능하며, 함수 사이에 무엇을 보존해야 하는지 먼저 타입으로 스케치하게 돼.

그렇다고 구현 전에 모든 타입을 완벽하게 설계하라는 뜻은 아니야. 작은 실행 조각과 타입을 번갈아 다듬으며 도메인 이해가 바뀔 때 계약도 고쳐야 해. 타입이 현실보다 앞서 독자적인 퍼즐이 되면 멈춰.

불가능한 상태 줄이기

로딩 중인데 데이터와 오류가 동시에 존재하는 객체보다 loading | ready | failed 판별 합집합이 의도를 잘 보여 줘. 공개 함수의 인자와 반환 타입은 호출자가 무엇을 준비하고 무엇을 기대할 수 있는지 드러내.

유효성 검사가 필요한 외부 값은 unknown에서 시작하고, 한 번 증명한 관계는 제네릭과 타입 가드로 보존해. 좋은 타입 설계는 주석을 많이 쓰는 일이 아니라 잘못된 조합을 적게 만드는 일이야.

객체 지향 원칙과 만나는 자리

캡슐화는 클래스의 private에만 있지 않아. 모듈이 내부 타입을 내보내지 않는 것도 캡슐화고, 인터페이스로 소비자가 필요한 능력만 보는 것도 추상화야. 제네릭은 여러 구체 타입에 같은 관계를 적용하고, 구조적 타입은 구현보다 모양에 의존하게 해.

상속이 언제나 좋은 객체 설계가 아니듯 복잡한 조건부 타입도 언제나 좋은 타입 설계는 아니야. 변경 이유가 같은 것을 묶고, 다른 것을 분리한다는 원칙이 두 층에 모두 적용돼.

타입으로 생각한다는 것은 컴파일러를 만족시키는 것이 아니라 상태, 경계, 관계를 구현 전에 말로 설명할 수 있게 만드는 일이야. 구현과 함께 그 설명을 계속 검증해.

Code

타입-first 설계·typescript
// Imperative-first 사고 — 구현이 타입 driving.
function loadConversation(id: string): unknown {
  // ... 코드 쓰고, 가면서 타입 알아냄
  return result;
}

// 타입-first 사고 — 설계가 구현 driving.
type ConversationLoadResult =
  | { status: 'success'; conversation: Conversation }
  | { status: 'not-found' }
  | { status: 'error'; error: Error };

async function loadConversation(id: string): Promise<ConversationLoadResult> {
  // 구현이 3 모양 중 하나 만들어야 — body 전에 놓임.
  try {
    const c = await fetchConversation(id);
    return c
      ? { status: 'success', conversation: c }
      : { status: 'not-found' };
  } catch (error) {
    if (error instanceof Error) return { status: 'error', error };
    return { status: 'error', error: new Error('unknown') };
  }
}

// Caller 가 discriminator 에 switch 하고 각 case 처리.
function render(r: ConversationLoadResult) {
  switch (r.status) {
    case 'success': return r.conversation.title;
    case 'not-found': return 'Not found';
    case 'error': return r.error.message;
  }
}

External links

Exercise

파서, 상태 머신, 작은 CRUD 작업처럼 범위가 작은 새 기능을 하나 골라. 구현은 하지 말고 20분 동안 타입만 설계한 뒤 실제 코드를 작성해. 구현부터 시작했을 때와 비교해 막다른 길과 전체 시간이 어떻게 달라지는지 기록해.
Hint
경계가 분명한 기능에서는 타입을 먼저 설계하면 구현 중의 막다른 길이 줄어 전체 시간이 대략 절반까지 줄 수 있어. 의존 코드가 생기기 전에 타입이 설계 문제를 드러내는지 살펴봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.