Skip to content
Back to skills

Codebase Design

ASecurity

작은 인터페이스 뒤에 많은 동작을 숨기는 deep module을 설계하기 위한 공용 어휘(module, interface, seam, adapter, depth)와 원칙

  • 111 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 2, 2026
ai-agentstypescriptrefactoringapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add Insajin/autopus-adk --skill codebase-design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Codebase Design?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Codebase Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/insajin-codebase-design/badge)](https://www.skillsdirectory.com/skills/insajin-codebase-design)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: codebase-design
description: 작은 인터페이스 뒤에 많은 동작을 숨기는 deep module을 설계하기 위한 공용 어휘(module, interface, seam, adapter, depth)와 원칙
compatibility: omp
---

# Codebase Design

**deep module**을 설계한다: 작은 인터페이스 뒤에 많은 동작, 깨끗한 seam에 놓이고, 그 인터페이스를
통해 테스트된다. 코드를 설계하거나 재구성하는 모든 자리에서 이 언어와 원칙을 쓴다. 목표는
호출자에게 leverage, 유지보수자에게 locality, 모두에게 testability다. 에이전트는 코딩을
가속하는 만큼 엔트로피도 가속하므로 설계에 *매일* 투자한다.

## 어휘

정확히 이 단어를 쓴다. "component", "service", "API", "boundary"로 바꿔 부르지 않는다.

- **Module**: 인터페이스와 구현을 가진 모든 것. 규모 무관 — 함수, 클래스, 패키지, 계층을
  가로지르는 슬라이스. _Avoid_: unit, component, service.
- **Interface**: 호출자가 모듈을 올바르게 쓰기 위해 알아야 하는 전부. 타입 시그니처뿐 아니라
  불변 조건, 호출 순서, 에러 모드, 필수 설정, 성능 특성, 그리고 **암묵 입력·출력**(cwd, 환경
  변수, ctx에 숨은 값, stdout/stderr, 파일 부수효과). 평가할 때 이 항목을 점검표로 훑는다.
  _Avoid_: API, signature(타입 표면만 가리켜 너무 좁다).
- **Implementation**: 모듈 안쪽의 코드 본체. **Adapter**와 구분한다 — 작은 adapter에 큰 구현
  (Postgres repo)도, 큰 adapter에 작은 구현(in-memory fake)도 있다.
- **Depth**: 인터페이스에서의 leverage. 호출자(또는 테스트)가 배워야 하는 인터페이스 단위당
  쓸 수 있는 동작의 양. 작은 인터페이스 뒤에 많은 동작이면 **deep**, 인터페이스가 구현만큼
  복잡하면 **shallow**.
- **Seam** _(Michael Feathers)_: 그 자리를 편집하지 않고 동작을 바꿀 수 있는 장소. 모듈의
  인터페이스가 *놓이는 위치*. 어디에 둘지는 무엇을 뒤에 둘지와 별개의 설계 결정이다.
  _Avoid_: boundary(DDD의 bounded context와 겹친다).
- **Adapter**: seam에서 인터페이스를 만족하는 구체물. 무엇이 들어 있는지가 아니라 어떤
  *역할*(슬롯)을 채우는지를 말한다.
- **Leverage**: depth가 호출자에게 주는 것. 배운 인터페이스 단위당 더 많은 능력. 구현 하나가
  N개 호출 지점과 M개 테스트에서 회수된다.
- **Locality**: depth가 유지보수자에게 주는 것. 변경, 버그, 지식, 검증이 여러 호출자로 퍼지지
  않고 한 곳에 모인다. 한 번 고치면 전부 고쳐진다.

## Deep vs shallow

```
deep:     ┌──────────────┐        shallow:  ┌──────────────────────────┐
          │ 작은 인터페이스 │                  │      큰 인터페이스        │
          ├──────────────┤                  ├──────────────────────────┤
          │              │                  │  얇은 구현(그냥 넘겨줌)     │
          │  깊은 구현     │                  └──────────────────────────┘
          └──────────────┘
```

인터페이스를 설계할 때 묻는다: 메서드 수를 줄일 수 있나? 파라미터를 단순화할 수 있나?
더 많은 복잡성을 안에 숨길 수 있나?

## 원칙

- **Depth는 구현이 아니라 인터페이스의 속성이다.** deep module 안쪽은 작고 교체 가능한 부품으로
  구성돼도 된다 — 인터페이스의 일부가 아닐 뿐. 모듈은 외부 seam 외에 자기 테스트가 쓰는
  **internal seam**을 가질 수 있다. 테스트가 쓴다는 이유로 internal seam을 인터페이스로
  노출하지 않는다.
- **삭제 테스트.** 모듈을 지운다고 상상한다. 복잡성이 사라지면 pass-through였다. 복잡성이
  N개 호출자로 다시 나타나면 제 몫을 하던 모듈이다. 판정할 때 운영 호출자 수, 테스트 호출자 수,
  사라지는 복잡성, 다른 곳으로 *이동*하는 복잡성을 따로 적는다 — 이동은 사라짐이 아니다.
- **인터페이스가 테스트 표면이다.** 호출자와 테스트는 같은 seam을 건넌다. 인터페이스 *너머*를
  테스트하고 싶다면 모듈 모양이 잘못됐을 가능성이 크다. 먼저 호출자가 관측해야 할 불변식
  (실패, 부수효과, 보안상 순서)과 교체 가능한 구현 세부(정확한 argv 배열, 명령 순서)를 가른다 —
  전자를 고정하는 테스트는 인터페이스 테스트고 후자를 고정하면 너머를 보는 것이다.
- **adapter 하나면 가설적 seam, 둘이면 진짜 seam.** 실제로 그 seam을 가로질러 변하는 것이
  없으면 seam(포트)을 만들지 않는다. adapter 하나짜리 seam은 그냥 간접화다. adapter는 운영과
  테스트를 나눠 *종류*로 센다; 테스트 adapter가 실제 fault(stale, tamper, 누락)를 나타내면 그
  seam은 internal seam으로 인정한다. 같은 역할의 람다 여럿은 하나다.

## Testability를 위한 설계

1. **의존성은 받는다, 만들지 않는다.** `processOrder(order, paymentGateway)`는 테스트 가능,
   함수 안에서 `new StripeGateway()`는 어렵다.
2. **결과를 반환한다, 부수효과를 내지 않는다.** `calculateDiscount(cart) Discount`는 테스트
   가능, `applyDiscount(cart)`가 `cart.total`을 고치면 어렵다.
3. **표면적을 작게.** 메서드가 적으면 테스트가 적고, 파라미터가 적으면 setup이 단순하다.

## Deepening: 의존성 범주별 테스트 전략

얕은 모듈 묶음을 깊게 합칠 때 의존성을 분류하고, 범주가 seam 너머 테스트 방식을 정한다.
한 모듈에 여러 범주가 섞이면(로컬 CLI가 원격 모델을 부르는 식) 모듈 전체가 아니라 **의존성마다**
분류하고 층을 나눈다.

| 범주 | 예 | 전략 |
|---|---|---|
| In-process | 순수 계산, 메모리 상태 | 합치고 새 인터페이스로 직접 테스트. adapter 불필요 |
| Local-substitutable | Postgres→PGLite, 메모리 FS | 대체물을 테스트 스위트에서 띄운다. seam은 internal |
| Remote but owned | 내부 서비스, 내부 API | seam에 port를 정의, 운영은 HTTP/gRPC adapter, 테스트는 in-memory adapter |
| True external | Stripe, Twilio | port로 주입, 테스트는 mock adapter |

**교체하되 겹치지 않는다**: 깊어진 모듈의 인터페이스 테스트가 생기면 얕은 모듈의 옛 단위
테스트는 낭비이므로 지운다. 구현이 바뀔 때 고쳐야 하는 테스트는 인터페이스 너머를 테스트하고
있는 것이다.

## Design it twice

첫 아이디어가 최선일 가능성은 낮다. 후보 인터페이스를 여러 개 놓고 비교한다:

1. 문제 공간을 먼저 사용자에게 설명한다 — 제약, 의존성과 그 범주, 제약을 구체화하는 스케치
   (제안이 아니다).
2. 서브에이전트 3개 이상을 **병렬**로 띄워 각각 *급진적으로 다른* 인터페이스를 만들게 한다.
   위임할 수 없는 환경(읽기 전용 worker, task 도구 없음)이면 혼자서 제약 축을 바꿔 가며 독립된
   설계 2개 이상을 순서대로 쓴다 — 첫 설계를 본 채로 두 번째를 쓰되, 첫 설계의 형태를 재사용하지
   않는 것이 규칙이다.
   Agent 1 "진입점 1~3개로 최소화, 진입점당 leverage 최대", Agent 2 "유연성·확장 최대",
   Agent 3 "가장 흔한 호출자에 최적화, 기본 케이스를 사소하게", 필요하면 Agent 4 "ports &
   adapters". 브리프에는 이 스킬의 어휘와 `CONTEXT.md`의 도메인 어휘를 함께 넣는다.
3. 각 설계를 순서대로 보여 준 뒤 **depth**, **locality**, **seam 위치**로 비교하고, 의견을 가진
   추천(필요하면 하이브리드)을 낸다. 메뉴가 아니라 강한 읽기를 준다.

## 거부한 프레이밍

- 구현 줄 수 / 인터페이스 줄 수 비율로서의 depth(Ousterhout): 구현 부풀리기를 보상한다.
  leverage로서의 depth를 쓴다.
- TypeScript `interface` 키워드나 public method로서의 "interface": 너무 좁다.
- "boundary": bounded context와 겹친다. **seam** 또는 **interface**라고 말한다.

관련 스킬: `refactoring`(동작 보존 변환), `entropy-scan`(hotspot 탐지), `tdd`(seam에서 테스트).

Adapted from mattpocock/skills `codebase-design` (MIT).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.