Communitygithub.com

Brians-brain/claude-skills

設計「深模組」(deep module)的共同詞彙:小介面背後放大量行為。當使用者想設計或改善模組的介面、找出可以把模組加深的地方、決定 seam(不必改程式就能替換行為的接縫)放在哪裡、讓程式碼更好測試或更容易讓 AI 理解,或其他 skill 需要這套設計詞彙時使用。

claude-skills란 무엇인가요?

이 스킬은 소프트웨어 설계, 특히 '깊은 모듈(deep module)' 개념을 중심으로 한 공통 어휘를 제공합니다. 개발자가 모듈의 인터페이스를 설계하거나 개선할 때, 또는 코드를 더 테스트하기 쉽게 만들거나 AI가 이해하기 쉽게 만들고 싶을 때 유용합니다. Claude Code, Cursor, Codex 등 모든 AI 에이전트 플랫폼에서 사용할 수 있으며, SKILL.md 파일에 정의된 일관된 용어(Module, Interface, Implementation, Depth, Seam, Adapter, Leverage, Locality)를 통해 팀 내 의사소통을 명확히 합니다. 이 스킬은 인터페이스의 크기와 복잡성을 최소화하면서 내부 구현에 복잡성을 숨기는 '깊은 모듈' 설계 원칙을 설명하고, 테스트 용이성을 위한 구체적인 예제(Python 코드)와 원칙을 제시합니다. 결과적으로 개발자는 코드의 유지보수성과 테스트 용이성을 높일 수 있습니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Brians-brain/claude-skills/tree/HEAD/codebase-design

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

코드 설계

사용자와 소통할 때는 한국어를 사용합니다. 다음 용어는 처음 등장할 때 영문과 함께 표기하고, 이후에는 통일된 용어로 사용합니다.

deep module 설계: 작은 인터페이스 뒤에 많은 행위를 숨기고, 깨끗한 seam 위에 배치하며, 그 인터페이스를 통해 테스트할 수 있도록 합니다. 코드를 설계하거나 리팩터링하는 모든 곳에서 이 언어와 원칙을 사용합니다. 목표는 호출자에게 레버리지(leverage)를, 유지보수자에게 지역성(locality)을 제공하고, 모든 사람이 쉽게 테스트할 수 있도록 하는 것입니다.

용어표

다음 용어를 정확히 사용하세요. '컴포넌트', '서비스', 'API', '경계' 등으로 바꾸지 마세요. 일관된 언어가 핵심입니다.

모듈(Module): 인터페이스와 구현을 모두 가진 모든 것. 규모를 의도적으로 제한하지 않습니다. 함수, 클래스, 패키지, 또는 여러 계층에 걸친 조각이 될 수 있습니다. 사용하지 말 것: 유닛, 컴포넌트, 서비스.

인터페이스(Interface): 호출자가 이 모듈을 올바르게 사용하기 위해 알아야 하는 모든 것: 타입 시그니처, 불변 조건, 호출 순서 제약, 오류 패턴, 필수 설정, 성능 특성. 사용하지 말 것: API, 시그니처(너무 좁아 타입 수준의 표면만 가리킴).

구현(Implementation): 모듈 내부, 즉 코드 본문. **어댑터(Adapter)**와 다릅니다. 어떤 것은 작은 어댑터에 많은 구현이 있을 수 있고(예: SQLite Repository), 어떤 것은 큰 어댑터에 적은 구현이 있을 수 있습니다(예: 인메모리 가짜 객체). Seam에 대해 논의할 때는 '어댑터'를, 그 외에는 '구현'을 사용합니다.

깊이(Depth): 인터페이스의 레버리지. 호출자(또는 테스트)가 인터페이스 단위 하나를 배울 때 얼마나 많은 행위를 사용할 수 있는지. 작은 인터페이스 뒤에 많은 행위가 숨겨진 모듈은 깊고, 인터페이스가 구현만큼 복잡한 모듈은 얕습니다.

Seam(Michael Feathers): 해당 위치를 수정하지 않고도 행위를 변경할 수 있는 지점, 즉 모듈 인터페이스가 위치한 장소. Seam을 어디에 둘 것인지는 그 자체로 설계 결정이며, seam 뒤에 무엇을 둘 것인지와는 별개입니다. 사용하지 말 것: 경계(DDD의 bounded context와 혼동됨).

어댑터(Adapter): 특정 seam에서 특정 인터페이스를 충족하는 구체적인 것. 내용(무엇이 들어 있는지)이 아니라 역할(어느 위치를 채우는지)을 설명합니다.

레버리지(Leverage): 호출자가 깊이로부터 얻는 이점. 인터페이스 단위 하나를 배울 때 더 많은 능력을 얻습니다. 하나의 구현 가치는 N개의 호출 지점과 M개의 테스트에서 회수됩니다.

지역성(Locality): 유지보수자가 깊이로부터 얻는 이점. 수정, 버그, 지식, 검증이 여러 호출 지점에 흩어지지 않고 한 곳에 집중됩니다. 한 번 수정하면 모든 곳에 적용됩니다.

깊음과 얕음

Deep module = 작은 인터페이스 + 많은 구현:

┌─────────────────────┐
│       작은 인터페이스     │  ← 메서드 적고, 매개변수 단순
├─────────────────────┤
│                     │
│      깊은 구현          │  ← 복잡한 로직이 내부에 숨겨짐
│                     │
└─────────────────────┘

얕은 모듈 = 큰 인터페이스 + 적은 구현 (피해야 함):

┌─────────────────────────────────┐
│             큰 인터페이스            │  ← 메서드 많고, 매개변수 복잡
├─────────────────────────────────┤
│  얇은 구현                         │  ← 단순히 전달만 함
└─────────────────────────────────┘

인터페이스를 설계할 때 스스로에게 물어보세요:

  • 메서드의 수를 줄일 수 있나요?
  • 매개변수를 단순화할 수 있나요?
  • 더 많은 복잡성을 내부에 숨길 수 있나요?

원칙

  • 깊이는 인터페이스의 속성이지, 구현의 속성이 아닙니다. Deep module의 내부는 작고, 모킹 가능하며, 교체 가능한 부품들로 구성될 수 있습니다. 단, 이러한 부품들은 인터페이스에 속하지 않습니다. 모듈은 내부 seam(구현 전용, 자체 테스트용)과 인터페이스 상의 외부 seam을 가질 수 있습니다.
  • 삭제 테스트. 이 모듈을 삭제한다고 상상해보세요. 복잡성이 사라진다면 단순한 전달자일 뿐입니다. 복잡성이 N개의 호출 지점에 다시 나타난다면, 제 역할을 하고 있는 것입니다.
  • 인터페이스는 테스트 표면입니다. 호출자와 테스트는 동일한 seam을 넘나듭니다. 인터페이스를 넘어 테스트하고 싶다면, 모듈의 형태가 잘못되었을 가능성이 높습니다.
  • 하나의 어댑터는 가상의 seam, 두 개의 어댑터는 진짜 seam입니다. 실제로 seam 양쪽에서 변화할 것이 없다면, seam을 도입하지 마세요.

테스트 용이성을 위한 설계

좋은 인터페이스는 테스트를 자연스럽게 만듭니다:

  1. 의존성을 직접 생성하지 말고, 주입받으세요.

    # 테스트 가능
    def fetch_alternates(mpn: str, client: PartSearchClient) -> list[Part]: ...
    
    # 테스트 어려움
    def fetch_alternates(mpn: str) -> list[Part]:
        client = DistributorClient(api_key=os.environ["DIST_API_KEY"])
    
  2. 부작용을 만들지 말고, 결과를 반환하세요.

    # 테스트 가능
    def landed_cost(bom: Bom, freight: Freight) -> Money: ...
    
    # 테스트 어려움
    def apply_landed_cost(bom: Bom) -> None:
        bom.total += freight_charge
    
  3. 작은 표면적. 메서드가 적을수록 필요한 테스트가 적고, 매개변수가 적을수록 테스트 준비가 간단합니다.

관계

  • 하나의 모듈은 정확히 하나의 인터페이스(호출자와 테스트에 제공하는 표면)를 가집니다.
  • 깊이는 모듈의 속성이며, 인터페이스로 측정됩니다.
  • Seam은 모듈의 인터페이스가 위치한 곳입니다.
  • 어댑터는 seam에 위치하며 인터페이스를 충족합니다.
  • 깊이는 호출자에게 레버리지를, 유지보수자에게 지역성을 제공합니다.

채택하지 않는 프레임워크

  • 깊이를 구현 라인 수와 인터페이스 라인 수의 비율로 정의하는 것(Ousterhout): 이는 구현을 부풀리도록 장려합니다. 우리는 '깊이는 레버리지'라는 정의를 사용합니다.
  • '인터페이스'를 Python의 Protocol/추상 클래스 또는 클래스의 public 메서드와 동일시하는 것: 너무 좁습니다. 여기서의 인터페이스는 호출자가 알아야 하는 모든 것을 포함합니다.
  • '경계': DDD의 bounded context와 혼동됩니다. seam 또는 인터페이스라고 말하세요.

추가 자료

  • 기존 의존성 하에서 모듈 그룹을 깊게 만드는 방법: DEEPENING.md 참조: 의존성 분류, seam 규율, '겹쳐 쌓기보다 교체' 테스트 전략.
  • 다양한 인터페이스 설계 탐구: DESIGN-IT-TWICE.md 참조: 여러 하위 에이전트를 병렬로 파견하여 몇 가지 근본적으로 다른 방식으로 인터페이스를 설계한 후, 깊이, 지역성 및 seam 위치를 비교합니다.

관련 스킬