---
name: Coupling
description: 결합도 원칙. 중복 코드 허용 판단 기준, Props Drilling 제거. toss/frontend-fundamentals 기반.
type: coding-standard
category: coupling
---

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

# 결합도 (Coupling)

> 코드를 수정했을 때의 영향 범위. 영향 범위가 좁고 예측 가능한 코드가 수정하기 쉽다.

## P-036 중복 코드 허용 판단 기준

무분별한 공통화는 불필요한 결합도를 만든다.
아래 질문에 하나라도 "예"라면 중복을 허용한다.

- 페이지마다 로깅 값이 달라질 수 있는가?
- 화면을 닫는 동작이 모든 곳에서 동일한가?
- 텍스트/이미지가 달라질 가능성이 있는가?

공통화는 "완전히 동일하게 유지될 것이 확실한 경우"에만 한다.

```typescript
// ❌ 억지 공통화 — closeView()가 페이지마다 다를 수 있음
export const useOpenMaintenanceBottomSheet = () => {
  return async (info: MaintenanceInfo) => {
    logger.log('점검 바텀시트 열림');
    const result = await maintenanceBottomSheet.open(info);
    if (result) logger.log('점검 바텀시트 알림받기 클릭');
    closeView(); // ← 페이지마다 다를 수 있는 로직이 고정됨
  };
};

// ✅ 중복 허용 — 각 페이지에서 직접 처리
// PageA.tsx
const result = await maintenanceBottomSheet.open(info);
if (result) logger.log('pageA_maintenance_alert_click');
router.back();

// PageB.tsx
const result = await maintenanceBottomSheet.open(info);
if (result) logger.log('pageB_maintenance_alert_click');
modal.close();
```

## P-037 Props Drilling 제거

prop이 3단계 이상 중간 컴포넌트를 통과하면 제거를 검토한다.

**우선순위: Composition 패턴 → Context API (최후 수단)**

```tsx
// ❌ ItemEditBody가 실제로 쓰지 않는 onClose를 중계
function ItemEditModal({ items, recommendedItems, onConfirm, onClose }) {
  return (
    <Modal onClose={onClose}>
      <ItemEditBody
        items={items}
        recommendedItems={recommendedItems}
        onConfirm={onConfirm}
        onClose={onClose} // ItemEditBody는 이걸 쓰지 않고 그냥 내려보냄
      />
    </Modal>
  );
}

// ✅ children Composition — 중계 불필요
function ItemEditModal({ items, recommendedItems, onConfirm, onClose }) {
  const [keyword, setKeyword] = useState('');
  return (
    <Modal onClose={onClose}>
      <ItemEditBody
        keyword={keyword}
        onKeywordChange={setKeyword}
        onClose={onClose}
      >
        <ItemEditList
          keyword={keyword}
          items={items}
          recommendedItems={recommendedItems}
          onConfirm={onConfirm}
        />
      </ItemEditBody>
    </Modal>
  );
}
function ItemEditBody({ children, keyword, onKeywordChange, onClose }) {
  return (
    <>
      <Input
        value={keyword}
        onChange={(e) => onKeywordChange(e.target.value)}
      />
      <Button onClick={onClose}>닫기</Button>
      {children}
    </>
  );
}
```

Context API는 테마, 로케일, 인증 상태 등 진짜 전역 상태에만 사용한다.
단순 Props Drilling 회피 목적으로 Context를 남용하지 않는다.
