a-philosophy-of-software-design

Rob Zapp 작성아직 설치 없음아직 좋아요 없음2026년 10월 8일 업데이트카테고리: 엔지니어링

무엇을 하나요

변경 사항이 내보내거나 가져올 수 있는 이름을 추가하거나, 모듈, 클래스, 컴포넌트, 헬퍼, 훅, 서비스 또는 래퍼를 생성하거나, 반복되는 코드를 중앙 집중화하거나, API를 변경할 때 코드를 작성, 변경 또는 검토할 때 사용하세요. Ousterhout 규칙(깊은 모듈, 정보 은닉, 복잡성 낮추기)과 코드 공유를 위한 불변 테스트, 독자 비용 테스트, 그리고 마지막에 필수 디자인 노트가 포함됩니다.

설치를 누르면 이 항목이 AgentsRoom 데스크톱 앱에서 열립니다. 앱이 아직 설치되어 있지 않으면 다운로드 페이지로 이동합니다.

SKILL.md

---
name: a-philosophy-of-software-design
description: 변경 사항이 내보내거나 가져올 수 있는 이름을 추가하거나, 모듈, 클래스, 컴포넌트, 헬퍼, 훅, 서비스 또는 래퍼를 생성하거나, 반복되는 코드를 중앙 집중화하거나, API를 변경할 때 코드를 작성, 변경 또는 검토할 때 사용하세요. Ousterhout 규칙(깊은 모듈, 정보 은닉, 복잡성 낮추기)과 코드 공유를 위한 불변 테스트, 독자 비용 테스트, 그리고 마지막에 필수 디자인 노트가 포함됩니다.
---

# 소프트웨어 설계의 철학 (John Ousterhout)

## 이 스킬을 사용할 때

코드를 설계, 작성, 변경 또는 검토할 때 이 스킬을 사용하세요. 모듈 설계, API 변경, 분해, 리팩토링, 이름, 주석, 테스트 및 성능 작업에 적용됩니다. 변경이 어색하게 느껴지거나 한 변경이 여러 파일에 걸쳐 퍼질 때도 사용하세요.

## 바로잡아야 할 편향

작동하는 코드는 단순한 코드와 같지 않습니다. 작은 조각, 익숙한 패턴, 플래그, 래퍼 및 추가 문서는 설계를 더 복잡하게 만들 수 있습니다. 이는 독자가 알아야 할 내용이 늘어나거나 다른 모듈에 지식이 누출될 때 발생합니다.

## 결정 규칙

- 설계는 복잡성을 얼마나 줄이는지로 측정하세요. 독자의 부담을 줄이는 설계를 선호하세요. 복잡성의 네 가지 징후는 다음과 같습니다. 한 변경이 여러 곳에서 수정을 필요로 한다. 의존성이 숨겨져 있다. 단계가 고정된 순서로 발생해야 한다. 독자가 많은 사실을 기억해야 한다.
- 설계를 지속적인 작업으로 다루세요. 작동하는 첫 패치가 나중 변경을 어렵게 만든다면 완성된 것이 아닙니다. 인터페이스, 모듈 분할 또는 추상화에 대한 결정 시 두 가지 이상의 설계를 비교하세요.
- 깊이 있는 모듈을 선호하세요. 깊이 있는 모듈은 작은 인터페이스를 가지고 많은 복잡성을 숨깁니다. 단순 전달 서비스, 얇은 라이브러리 래퍼 및 작은 헬퍼 모듈을 거부하세요. 이름만 추가하고 독자의 부담을 줄이지 않는 추출도 거부하세요.
- 인터페이스는 호출자가 알아야 할 것에 맞춰 설계하고 구현 방식에 맞추지 마세요. 취약한 설정 순서, 모드 플래그, 구성 조절기 및 내부 선택을 드러내는 인수는 피하세요.
- 변경될 수 있는 결정은 숨기세요. 예를 들어 내부 표현, 저장 형태, 프로토콜, 파일 형식 및 성능 트릭이 있습니다. 장부 관리, 정규화 및 예외 처리도 해당됩니다. 각 항목은 그 지식을 소유한 모듈 내에 유지하세요.
- 복잡성을 세부 사항을 소유한 모듈로 끌어내리세요. 호출자에게 더 단순한 계약을 제공하고 각 호출 지점에서 반복 작업을 제거한다면 더 복잡한 구현을 받아들이세요.
- 모듈은 적절한 수준에서 일반적으로 만드세요. 한 호출자에 맞추지 마세요. 미래 필요를 위한 모호한 추상화를 추가하지 마세요. 드문 예외는 주 경로에서 제외하고 특수 동작은 별도의 장소에 두세요.
- 모듈을 합치거나 분할할 때는 전체 복잡성으로 판단하세요. 크기, 코드 실행 순서, 습관 또는 외관으로 판단하지 마세요. 관련 상태, 동작, 규칙 및 결정을 함께 유지하세요. 새 경계가 더 깊고 독자가 각 측면을 혼자 이해할 수 있을 때만 분할하세요.
- 예외 집합을 작게 만드세요. 가능하면 인터페이스나 규칙을 변경해 잘못된 상태가 발생하지 않도록 하세요. 모든 호출자가 같은 방어 코드를 반복하지 않도록 하세요.
- 주석을 사용해 복잡성을 줄이세요. 인터페이스 계약, 반드시 지켜야 할 규칙, 숨겨진 설계 결정 및 그 이유를 기록하세요. 호출자가 알 필요 없는 어려운 사실도 적으세요. 코드를 주석으로 반복하지 마세요. 나쁜 이름, 나쁜 분할 또는 혼란스러운 제어 흐름을 숨기기 위해 주석을 사용하지 마세요.
- 이름, 일관성 및 명확성을 설계 정보로 다루세요. 이름은 독자에게 추상화를 알려주고 메커니즘을 알려주지 않습니다. 관련 작업은 같은 규칙을 사용합니다. 독자를 놀라게 하는 코드는 짧더라도 복잡성을 더합니다.
- 공개 계약과 안정적인 API에 대해 테스트를 작성하세요. 숨겨진 복잡성과 특수 사례는 그 계약을 통해 테스트하세요. 테스트의 용이성 때문에 얕거나 누출되는 인터페이스를 강요하지 마세요.
- 성능 변경, 패턴, 패러다임 또는 프레임워크는 두 가지 이유 중 하나일 때만 추가하세요. 이 코드베이스의 복잡성을 줄이거나, 증거가 그 절충이 필요함을 보여줄 때입니다. 각 최적화는 안정적인 인터페이스 뒤에 숨기세요.

## 신호와 각각에 대한 대응

- 기능이 어색하거나 한 변경이 여러 파일에 걸쳐 퍼지거나 리뷰어가 숨겨진 의존성을 찾아야 할 때. 대응: 정보 은닉이 부족하거나 얕은 모듈을 찾아보세요. 고정된 순서의 단계와 호출자가 부담하는 복잡성도 찾아보세요.
- 모듈, 계층, 서비스, 헬퍼, 래퍼 또는 퍼사드를 추가하거나 패턴, 옵션, 콜백 또는 인수를 추가할 때. 대응: 추가하는 복잡성보다 더 많은 복잡성을 숨기는지 보여주세요.
- API를 변경할 때. 대응: 일반 호출자가 알아야 할 것을 확인하세요. 호출자는 호출 순서, 표현 또는 저장 방식을 알 필요가 없습니다. 호출자는 전송, 캐시, 프로토콜 또는 파일 형식을 알 필요가 없습니다. 호출자는 내부 워크플로우나 많은 설정 단계를 알 필요가 없습니다.
- 호출자가 볼 수 있는 특수 사례, 플래그, 예외 경로, 조건 또는 컨테이너를 추가할 때. 대응: 먼저 소유 모듈이 대신 할 수 있는지 물어보세요. 잘못된 상태를 제거하거나, 특이 동작을 격리하거나, 더 강력한 동작을 제공할 수 있습니다.
- 코드를 분할하거나 함수를 추출하거나 변수를 추가할 때. 대응: 새 경계나 이름이 의미를 가지는지 확인하세요. 단지 점프, 통과하는 상태 또는 호출자가 볼 수 있는 중간 단계만 추가해서는 안 됩니다.
- 코드에 `prepare`, `process`, `finalize` 같은 단계가 있거나 호출자가 객체를 단계별로 만들어야 할 때. 대응: 시간 순서가 진짜 개념인지 확인하세요. 아니라면 안정적인 책임에 맞춰 코드를 조직하세요.
- 이름이 모호하거나 메커니즘을 이름 짓거나 일관성이 없거나 독자를 놀라게 할 때. 대응: 추상화 경계에 대해 다시 생각하세요. 거의 맞는 이름을 받아들이지 마세요.
- 주석이 길거나 코드를 반복하거나 혼란스러운 인터페이스를 설명하거나 사용법을 설명하기 위해 내부를 보여줄 때. 대응: 추상화를 변경하거나 누락된 계약을 인터페이스로 옮기세요.
- 성능을 최적화할 때. 대응: 먼저 측정하고 최적화를 숨기세요. 절충이 필요하다는 증거 없이는 모듈 깊이 또는 정보 은닉을 포기하지 마세요.
- 테스트하거나 리뷰할 때. 대응: 공개 동작과 인터페이스 계약을 보세요. 안정적인 API 뒤에 숨겨진 복잡성과 추상화 뒤에 유지되는 특수 사례도 보세요.

## 최종 점검표

- 변경 사항이 시스템을 이해하고, 변경하고, 검증하며 확장하는 노력을 줄여주는가?
- 각 인터페이스 요소, 래퍼, 레이어, 헬퍼, 옵션 및 이름이 숨겨야 할 복잡성을 충분히 숨기고 있는가?
- 중요한 결정이 한 곳에 모여 있는가? 의존성이 명확한가? 호출자가 알아야 할 제약 조건이 문서화되어 있는가? 변경될 수 있는 내부는 보호되고 있는가?
- 일반적인 경우가 추가 단계 없이 작동하는가? 드문 제어, 특수한 경우, 성능 트릭 및 예외 세부사항이 일반 경로에서 벗어나 있는가?
- 이름이 정확하고 일관된가? 주석이 최신이며 코드의 반복이 없는가? 코드는 기존 관례를 따르고 있으며, 새로운 정보가 변경 이유가 되지 않는 한 관례를 변경하지 않는가?

## Gate

다른 코드가 내보내거나 가져올 수 있는 이름을 추가하는 변경 시 전체 체크리스트를 사용하세요. 모듈, 클래스, 컴포넌트, 헬퍼, 훅, 서비스 또는 래퍼를 생성하거나 반복되는 코드를 한 곳에 모을 때도 사용하세요. 이름 변경, 코드 변환, 구성 변경, 데이터 변경 및 한 줄 수정은 필요하지 않습니다.

## 불변 테스트: 함께 변경되는 코드만 공유하기

- 이름을 붙일 수 있는 규칙을 보호할 때만 공유 코드를 추출하세요. 증거는 함께 변경된 이력입니다: 복사본들이 함께 수정되거나 변경된 기록이 있어야 합니다. 단지 비슷해 보이고 독립적으로 변경되는 코드는 운율(rhyme)입니다. 운율은 중복으로 남겨두세요. 세 개의 비슷한 블록이 규칙을 증명하지 않습니다.
- 수정은 문제를 제거해야 하며, 문제를 옮기면 안 됩니다. 여섯 개의 캐스트를 하나의 일반 캐스트 헬퍼로 옮겨도 여전히 여섯 개의 캐스트입니다. 캐스트가 숨기고 있던 타입 매퍼를 작성하세요.
- 추상화가 잘못되었으면 코드를 다시 인라인으로 넣고 중복이 돌아오게 하세요. 플래그로 추상화를 억지로 구부리지 마세요.
- 크기 때문에만 코드를 분할하지 마세요. 하나의 400줄 모듈이 하나의 결정을 숨기는 것이 네 개의 100줄 모듈이 같은 조인을 누출하는 것보다 낫습니다.
- Clean Code나 SOLID(매우 작은 함수, 각 책임마다 하나의 클래스)를 기계적으로 적용하면 얕은 모듈이 됩니다. 이 스킬이 그 압력보다 우선합니다.

## 독자 비용: 세 번째 테스트

깊이 테스트와 불변 테스트는 경계가 존재해야 하는지 결정합니다. 독자 비용 테스트는 경계 주변 코드가 변경하기 쉬운지 결정합니다. 다음 독자, 사람 또는 에이전트는 읽어야 할 각 줄마다 비용을 지불합니다. 에이전트는 토큰으로 비용을 지불합니다. 에이전트는 텍스트 검색, 부분 읽기, 타입 검사 및 테스트로 코드를 찾습니다.

- **찾기 쉬움.** 각 개념에 하나의 이름을 사용하세요. 어디서나 동일하게 철자하여 일반 텍스트 검색으로 찾을 수 있게 하세요. 결함: 문자열로 만든 이름, import 부작용을 통한 연결, 하나의 개념에 두 개의 이름. 정의를 숨기는 재내보내기 체인도 결함입니다.
- **조기 중단.** 계약을 파일 상단이나 export 위에 두세요. 약속하는 것, 숨기는 것, 절대 하지 않는 것을 명시하세요. 그러면 독자가 일찍 멈출 수 있습니다.
- **기계 검증 가능.** 각 경계의 입출력에 정확한 타입을 사용하여 타입 검사가 호출자 읽기를 대체하게 하세요. 결함: `any`, 일반 딕셔너리, 본문에만 의미가 있는 불리언 플래그.
- **명확한 결합.** 두 곳이 함께 변경되어야 합니다. 공유 타입, 테스트 또는 단일 소스로 이를 강제하세요. 불가능하면 두 곳에 표시하세요.
- **잡음 없음.** 코드를 반복하는 주석과 주석 처리된 코드를 제거하세요. 죽은 분기와 변경 이력을 기록하는 주석을 제거하세요. 대체 경로 옆에 남아 있는 오래된 경로를 제거하세요.
- **예측 가능.** 저장소의 기존 레이아웃을 따르세요. 독자가 찾는 곳에 테스트를 두고 단독으로 실행되게 하세요.

파일 크기는 의도적으로 이 목록에 포함하지 않았습니다. 매우 큰 파일은 두 번째 숨겨진 결정을 찾을 이유입니다. 파일을 자르는 이유는 절대 아닙니다.

## 안전성

기존 코드의 경우 현재 동작을 유지하는 테스트를 먼저 작성하세요. 그런 다음 모듈을 더 깊게 만드세요. 새 코드의 경우 의도한 동작을 정의하는 테스트를 작성하세요.

## 설계 노트 (Gate가 적용될 때 필수)

Gate가 적용되면 풀 리퀘스트 설명에 `## Design note` 제목의 섹션을 추가하세요. 두 줄에서 네 줄 정도 작성하세요:

- 추가한 각 경계와 숨긴 결정.
- 의도적으로 유지한 각 중복과 그 이유.
- 수용한 각 얕은 부분과 그 이유.

Gate가 적용되지 않으면 `## Design note` 다음에 `Gate not applicable: <이유>`를 작성하세요. 또한 최종 단계 요약에도 설계 노트를 포함하세요.

## 리뷰 모드

다른 에이전트나 사람이 작성한 코드를 리뷰하거나 테스트할 때 이 섹션을 사용하세요.

1. 설계 노트를 확인하세요. Gate가 적용되고 풀 리퀘스트에 `## Design note` 섹션이 없으면 차단 사유를 보고하세요. 노트가 diff와 일치하지 않으면 차단 사유를 보고하세요.
2. 설계 발견 사항은 다음 두 조건을 모두 만족할 때만 차단 사유입니다:
   - 이 스킬의 규칙을 명명합니다. 규칙은 결정 규칙, Gate, 불변 테스트 또는 독자 비용 항목 중 하나입니다.
   - 독자나 다음 변경에 구체적인 비용을 명시합니다. 예: "호출자는 저장소 형태를 알아야 한다." "하나의 개념에 두 개의 이름이 있다." "캡 변경은 세 개 파일의 수정을 필요로 한다."
3. 다른 모든 설계 관찰은 비차단으로 표시하세요. "비차단 설계 노트" 제목의 별도 목록에 넣으세요. 비차단 노트는 작업을 작성자에게 되돌리지 않습니다.
4. 선호 사항은 발견 사항으로 보고하지 마세요. 다른 이름, 파일 레이아웃 또는 스타일은 선호 사항입니다. 명명된 규칙을 깨고 구체적인 비용이 있을 때만 발견 사항이 됩니다.
5. 동일한 설계 발견 사항이 두 번째 리뷰 주기에서 다시 나오면 에스컬레이션하세요. 세 번째로 같은 변경을 요청하지 마세요.

## 관련 스킬 (설치된 경우)

- `find-shared-code`: 공유할 가치가 있는 코드를 최근 이력에서 보고만 하는 검색입니다. 이 스킬의 불변 테스트와 깊이 테스트를 사용합니다.
- `refactoring` 및 `working-effectively-with-legacy-code`: 더 깊은 설계를 향한 안전한 단계입니다. 이 스킬이 새 경계가 유지되는지 결정합니다.

## 출처 및 라이선스

이 스킬은 GitHub의 ciembor/agent-rules-books 저장소에 있는 "A Philosophy of Software Design"의 "mini" 규칙들(MIT 라이선스, 커밋 893a88a)을 기반으로 합니다. 게이트, 불변성 테스트, 리더 비용 테스트, 설계 노트, 리뷰 모드는 해당 규칙들에 추가된 내용입니다. 이 저장소에는 책의 전체 규칙도 포함되어 있습니다.

태그

designarchitectureousterhoutreview

더 알아보기

AgentsRoom 다운로드

모든 AI 에이전트를, 모든 프로젝트에서, 하나의 창으로 실행하세요.

무료AgentsRoom 다운로드

컴패니언 앱: 이동 중에도 에이전트를 모니터링

Claude, Codex, Antigravity CLI 또는 다른 AI 공급자를 사용하세요.

확장 프로그램 설치
Chrome Web Store

버그와 요청을 공개 백로그로 바로 보내세요.

멀티 프로젝트
멀티 프로바이더
멀티 에이전트
실시간 상태
파일 diff & 커밋
모바일 앱
라이브 프리뷰
에이전트 팀
브라우저 자동화
백로그 기반 개발
프롬프트 라이브러리
스킬 라이브러리
모든 기능 보기