Deep Modules — AI 시대에 가장 직접적으로 부활하는 원칙
Ousterhout — A Philosophy of Software Design의 가장 핵심 원칙. Matt 강연이 AI agent의 shallow 양극화 약점을 deep module로 보완한다고 호출한 자리. overview의 1순위 원칙.
한 줄
Module의 가치 = (감추는 복잡성) ÷ (노출하는 복잡성). Deep module은 이 비율을 극대화하는 design — 작은 interface, 깊은 implementation. AI agent의 가장 큰 약점이 shallow module 양산이라서, 2026년 fundamentals 회귀의 가장 구체적이고 실용적인 답이 됐다.
⚛️ 철학
원칙의 왜. 더 깊은 root와의 연결.
Ousterhout의 책 A Philosophy of Software Design은 complexity의 누적이 시스템 죽음의 원인이라는 한 명제 위에 서 있다. 그 명제 아래 deep module은 complexity를 처리하는 단위로 정의된다.
Module의 가치 공식:
Module의 net benefit = (감춘 complexity) - (interface로 노출한 complexity)
이 공식이 정직하게 보여주는 사실:
- interface가 implementation만큼 복잡하면 net benefit ≈ 0
- shallow module은 추상화의 비용을 갚지 못하는 추상화
- 사용자가 module을 쓰려고 내부 동작까지 알아야 한다면, module 경계는 환상
이게 더 깊은 root인 information-hiding (Parnas, 1972)의 운영 표현이다. Parnas의 원본 명제는 "design decision은 module 안에 감춰져야 한다". Ousterhout은 이걸 *"interface와 implementation의 비율"*로 측정 가능하게 만들었다.
또 하나의 root는 strategic-vs-tactical-programming. shallow module의 양산은 tactical 사고의 직접 결과 — 매 순간 "돌아가는 코드"만 만들면 추상화가 표면적으로만 그려진다. Deep module은 strategic 사고가 누적된 형태.
simple-not-easy와의 연결: deep module은 simple하지만 easy하지 않다. 만들기 어렵지만, 그 어려움이 내부에 갇혀 있다. shallow module은 만들기 easy하지만 시스템 전체로 보면 *복잡 (complex)*하다.
🧱 추상적 작동 구조
Module은 complexity 통의 두께가 다른 두 모양으로 나뉜다.
핵심 비율 그림:
대표 deep module 사례 (Ousterhout이 책에서 호출):
- Unix file system call —
read(fd, buf, n). interface는 정수 3개. 내부에는 disk scheduling, cache, permission, journal, network FS 등 수십 년의 design decision이 갇혀 있음 - Garbage collector — interface는 거의 없음 (
new, 끝). 내부에는 generational, mark-sweep, compaction, write barrier 등 - TCP socket —
socket / connect / send / recv / close5개. 내부에는 reliability, congestion control, retransmission, flow control
Shallow의 anti-pattern (Ousterhout 책 호출):
- PassThrough method — 그냥 다른 method로 위임만
- Class explosion — 한 conceptual unit이 작은 class 10개로 쪼개짐
- Deep call chain with no logic — 5단계 호출이 전부 forwarding
⚠️ 약점/한계
원칙의 적용 한계. 감추지 않으면 함정에 빠짐.
1. Over-encapsulation → God Class 위험 "deep하게"를 기계적으로 적용하면 한 module이 너무 많은 책임을 갖게 됨. SRP(Single Responsibility)와 충돌. 이건 deep이 잘못 정의된 경우다 — cohesive하지 않은 깊이는 god class. cohesive한 깊이만 deep module.
2. Debugging 곡선의 가파름 Deep module은 내부가 풍부하므로 버그 발생 시 trace가 어려움. shallow는 reading은 쉬움 (forwarding이 다 보임). Deep module은 좋은 logging·observability가 필수 동반.
3. 학습 곡선의 처음 가파름 새 contributor는 deep module의 내부 모델을 학습해야 함. shallow는 코드 읽기만으로 진입 가능. → 이 약점은 ironically deep module의 장점이기도 하다 — 학습한 사람은 interface만 보면 일을 진행할 수 있음. shallow는 영원히 내부를 봐야 함.
4. 얕은 깊이의 함정 (deep shallow module) Interface는 좁은데 implementation도 얇은 경우. 예: getter/setter wrapper class, dataclass with 1 method. 이건 deep도 shallow도 아니라 낭비.
5. 추상화의 비용 ↔ 이득 trade-off가 도메인에 의존
- 작은 utility (string padding, math 함수): 추상화 비용 자체가 낮으므로 deep도 shallow도 차이 작음
- 안정적인 도메인 (CRUD UI): shallow도 충분
- 변화 잦은 도메인 (LLM provider, 외부 API): deep이 변화 흡수의 핵심
6. 너무 deep하면 testability 저하 내부가 복잡할수록 unit test로 cover하기 어려움. integration test로 보완해야 하는데, integration test는 느리고 깨지기 쉬움. → deep module은 잘 정의된 internal seam이 필요.
🔄 대안 흐름
이 원칙이 적용 안 되는 시나리오와 다른 답.
Shallow module이 더 맞는 경우들:
| 상황 | 왜 shallow | 예시 |
|---|---|---|
| Glue code / adapter | 두 안정적 인터페이스 사이 얇은 변환만 필요. 깊이 만들 게 없음 | HTTP → 내부 함수 mapper |
| 작은 utility | 추상화 비용 자체가 낮아서 깊이 불필요 | slugify(text), clamp(n, min, max) |
| Pure data type | data + getter/setter. 동작 없음 | DTO, value object |
| 실험 코드 / spike | reversibility 우선. 가볍게 만들고 버림 | proof-of-concept |
| Glue between deep modules | 자기 자체는 얇지만 깊은 module들을 조립 | application service layer |
다른 조직 패러다임과의 비교:
각 패러다임은 trade-off가 다르다. Deep module과 microservices는 직접 충돌 — 작은 service 다수는 shallow module의 시스템 단위 표현. Microservices가 적합한 영역은 조직 boundaries · 독립 배포 · scale isolation. Deep module이 적합한 영역은 추상화 안정성 · 학습 곡선 압축.
대부분의 실무 시스템은 둘을 조합 — service 안에 deep module, service 사이는 microservices.
💡 인사이트
AI 시대 왜 지금 부활하는가 + 학내 segment 의미.
1. AI agent의 가장 직접적 약점이 deep module로 보완된다
Matt이 강연에서 명시:
"AI agents are particularly good at generating shallow modules."
왜인가? AI agent가 코드를 incremental하게 짓기 때문. 한 prompt = 한 파일. 한 task = 한 새 abstraction. 누적되면 작은 파일 100개가 양산되고, 그 안에는 forwarding과 thin wrapper만 가득해진다. 이게 research/stateless-llm-sdk/fundamentals-lineage|fundamentals-lineage에서 정리한 AI 시대 4 problem 중 problem 2의 직접 형태.
해결의 정확한 모양: 사람이 strategic하게 module 경계를 정해주면, AI는 그 안에서 깊이를 채울 수 있다. AI는 경계 자체는 못 정해도, 정해진 경계 안에서 implementation을 깊게 짓는 것은 잘한다. 이게 strategic-vs-tactical-programming의 직접 적용.
2. AI agent의 navigation 한계가 deep module을 강요한다
LLM의 context window는 제한된다. 100개 작은 파일을 동시에 navigate하는 건 사실상 불가능 — context가 망가지거나 file lookup loop에 빠진다. Deep module 5개는 그 자체로 agent에게 인지 가능한 단위. 이게 research/stateless-llm-sdk/fundamentals-lineage|Karpathy reverse 흐름의 실용적 근거 중 하나.
3. v1.0 design에 직접 적용된 사례 (재확인)
research/stateless-llm-sdk/design-principles|7 원칙의 원칙 1이 deep module이고, 구체 적용은:
| layer | interface 크기 | 안에 갇힌 complexity |
|---|---|---|
Provider trait | method 4개 | vendor별 quirk, retry, cache, rate limit |
SKILL.md frontmatter | field 5-7개 | lazy loading, context budget, tool whitelist, owner, success criteria |
| agent loop crate | run(prompt) -> Result | turn, tool dispatch, context compaction, failure mode |
이 사례들이 deep module이 theory가 아니라 실용적 design 도구임을 입증.
4. 학내 segment에서의 고유한 의미
학내 통합 모듈은 deep module이 특히 잘 맞는다:
- 외부 인터페이스(학사 시스템 API, 인증 시스템)는 변동 잦음 + 학기마다 개편
- 사용자(학생)에게 노출되는 표면은 학내 vocabulary로 좁아야 함 (ubiquitous-language 원칙)
- 그 사이에 깊은 변환·캐싱·정책 layer가 deep module 안에 갇혀야 함
→ 학내 통합 모듈의 외부 표면 = "수강신청 가능 과목 조회". 내부에는 학사 API 호출, 학번 인증, 시간표 충돌 검사, 졸업요건 lookup이 모두 갇힘. 이게 deep module의 학내 표현.
5. 얕은 깊이의 자기 점검
새 module을 만들 때마다 묻는 질문:
- interface 크기는 얼마인가? (method 수, parameter 수, 학습 시간)
- implementation에 갇힌 complexity는 무엇인가? 구체적으로 나열할 수 있는가?
- 비율이 interface < implementation인가? 아니면 비슷한가?
- 비슷하다면: 이 module의 추상화 비용을 다른 module에서 갚을 방법이 있는가? 없다면 합치거나 제거.
이 질문들이 매 design 결정마다 자연스럽게 deep module을 유지하는 도구.
6. AI에게 deep module을 짓게 하는 패턴
학내 사용자가 v1.0으로 자기 도구를 만들 때 사용할 패턴:
- 사람이 interface 명세만 먼저 적음 (
SKILL.mdfrontmatter, trait 정의) - AI에게 그 interface 안에서 모든 동작을 implementation
- AI가 새 method를 추가하려 하면 push back (사람이 strategic 결정)
- 매 step에서 interface가 그대로 유지되는지 검증 (tdd-as-small-deliberate-steps 동반)
→ deep module은 AI에게 위임할 수 있는 단위가 되고, interface는 사람의 strategic 결정 표면이 된다. 이 분할이 research/stateless-llm-sdk/software-fundamentals-thesis|Matt thesis의 핵심.
다음에 가야 할 자리
이 노트가 호출한 다른 원칙들 — 자연스러운 다음 노트:
- information-hiding — deep module의 더 깊은 root (Parnas 1972). 왜 감춰야 하는가
- strategic-vs-tactical-programming — interface는 strategic, implementation은 tactical 분할의 직접 표현
- information-leak-vs-abstraction — deep module의 자기 점검 도구. 언제 leak이 발생하는가
- simple-not-easy — deep module은 simple하지만 easy하지 않다는 명제
관련
- overview
- research/stateless-llm-sdk/software-fundamentals-thesis|software-fundamentals-thesis — Matt thesis ("AI shallow 양산 약점")
- research/stateless-llm-sdk/design-principles|design-principles — 원칙 1 (Deep Modules over Shallow)
- research/stateless-llm-sdk/fundamentals-lineage|fundamentals-lineage — AI 시대 4 problem 중 problem 2
Sources
직접 source
- A Philosophy of Software Design — John Ousterhout (2018, Stanford). 책 전체에서 deep module 챕터(4장)가 핵심
- Ousterhout — A Philosophy of Software Design YouTube talk (Stanford) — 1시간 압축
원리의 root
- Parnas, D.L. (1972). On the Criteria to Be Used in Decomposing Systems into Modules. CACM 15(12). — Information Hiding 원본 논문 (deep module의 더 깊은 root)
- Rich Hickey — Simple Made Easy (InfoQ, 2011) — simple ≠ easy 명제
AI 시대 호출
- Matt Pocock — "Software Fundamentals Matter More Than Ever" YouTube — "AI agents are particularly good at generating shallow modules" 명시
- mattpocock/skills GitHub —
/improve-codebase-architecture— deep module 자동화 skill
대안 패러다임 (대안 흐름 섹션의 비교 대상)
- Bernhardt, Gary. Functional Core, Imperative Shell (talk)
- Newman, Sam. Building Microservices (2nd ed.)