---
name: Predictability
description: 예측 가능성 원칙. 같은 이름은 같은 동작, 반환 타입 통일, 숨은 로직 제거. toss/frontend-fundamentals 기반.
type: coding-standard
category: predictability
---

> 출처: 팀 공통 원칙 문서 `principles/` 2026-07-03 발췌. 원칙 개정은 원본(팀 공통 문서) 먼저, 이 사본은 따라간다.

# 예측 가능성 (Predictability)

> 함수나 컴포넌트의 동작을 이름·파라미터·반환 값만 보고도 예측할 수 있는 코드.

## P-031 같은 이름은 같은 동작

라이브러리와 동일한 이름의 함수/변수를 만들지 않는다. 동작이 다르면 다른 이름을 써야 한다.

```typescript
// ❌ 라이브러리 http와 같은 이름 — 토큰 추가라는 숨은 동작 있음
import { http as httpLibrary } from '@some-library/http';
export const http = {
  async get(url: string) {
    const token = await fetchToken(); // 예상 못한 부수 효과
    return httpLibrary.get(url, {
      headers: { Authorization: `Bearer ${token}` },
    });
  },
};

// ✅ 이름으로 동작을 명확히 표현
export const httpService = {
  async getWithAuth(url: string) {
    const token = await fetchToken();
    return httpLibrary.get(url, {
      headers: { Authorization: `Bearer ${token}` },
    });
  },
};
```

## P-032 같은 종류의 함수는 반환 타입 통일

같은 종류의 함수(예: API Hook, 유효성 검사 함수)는 반환 타입을 일관되게 유지한다.
유효성 검사 함수가 `boolean`과 `객체`를 혼용하면 객체는 항상 truthy라 버그가 발생한다.

```typescript
// ❌ Hook 반환 타입 불일치
function useUser() { return useQuery({ ... }); }           // Query 객체 반환
function useServerTime() { return useQuery({...}).data; }  // data만 반환

// ✅ 모두 Query 객체로 통일
function useUser() { return useQuery({ ... }); }
function useServerTime() { return useQuery({ ... }); }
```

```typescript
// ❌ 유효성 검사 함수가 boolean / 객체 혼용
// 객체는 항상 truthy라 if (checkIsAgeValid(age))가 항상 실행됨
function checkIsNameValid(name: string) {
  return name.length > 0;
} // boolean
function checkIsAgeValid(age: number) {
  return { ok: false, reason: '...' };
} // 객체

// ✅ Discriminated Union으로 통일
type ValidationResult = { ok: true } | { ok: false; reason: string };
function checkIsNameValid(name: string): ValidationResult {
  if (name.length === 0)
    return { ok: false, reason: '이름은 빈 값일 수 없어요.' };
  return { ok: true };
}
function checkIsAgeValid(age: number): ValidationResult {
  if (age < 0) return { ok: false, reason: '나이는 0 이상이어야 해요.' };
  return { ok: true };
}
```

## P-033 숨은 로직 드러내기

함수 시그니처(이름·파라미터·반환 값)에 드러나지 않는 side effect를 함수 내부에 숨기지 않는다.
순수한 함수와 side effect는 분리하고, 호출부에서 명시적으로 처리한다.

```typescript
// ❌ fetchBalance가 로깅이라는 숨은 부수 효과를 가짐
// 로깅 오류 시 잔액 조회 전체가 망가짐
async function fetchBalance(): Promise<number> {
  const balance = await http.get<number>('...');
  logging.log('balance_fetched'); // 숨겨진 부수 효과
  return balance;
}

// ✅ 순수 fetch + 호출부에서 명시적 로깅
async function fetchBalance(): Promise<number> {
  return await http.get<number>('...');
}

const balance = await fetchBalance();
logging.log('balance_fetched'); // 호출부에서 명시적으로
await syncBalance(balance);
```
