
13장
(part1은 17장까지 있다는 사실을 알고 계시나요? 곧 파트1이 끝난다는 뜻입니다! 끼얏호우)
Part1. Code
Chapter13. Clean Classes
7장에서 배운 '함수를 작게, 한 가지만' 원칙을
한 단계 위인 클래스/모듈에도 똑같이 적용하자.
7장에서 우리가 배운 것은...
1-7장: Clean Functions https://developer-dreamer.tistory.com/204
1. 함수는 '개념의 조각'을 담는 그릇이다 - 선언하고, 호출하고, 재사용할 수 있는 논리적 단위
2. 하나의 함수에 여러 개념을 넣을 수 있지만, 작고 명확한 단위로 쪼개는 게 낫다
Classes and Modules vs Files
이 장의 주제는 '파일을 어떻게 나누냐'가 아니다.
'개념을 어떻게 묶느냐'가 주제다.
TypeScript는 파일 1개에 클래스를 여러 개 둘 수도 있고, 클래스 1개를 여러 파일에 나눌 수도 있다.
하지만, 할 수 있다고 해서 해야하는 것은 아니다.
일반적으로 소스 파일 하나에 모듈이나 클래스 하나만 두는 게 가장 다루기 편하다.
What Should a Class Contain?
클래스에는 무엇을 넣어야 할까?
극단적인 케이스를 보자.
모놀리스: 모든 메서드를 클래스 하나에 넣기. 모든 게 뒤섞여 찾기 힘듦.
메서드당 클래스 1개: 함수마다 클래스 만듦. 지나친 파편화로 전체 흐름 파악 힘듦
제대로된 구조 없이 시스템이 커지면 이런 일이 벌어진다.
1. 코드를 못 찾는다 - 이 로직 어딨지? 파일 무한히 뒤져보기
2. 중복이 증가한다 - 같은 로직이 여기저기 복사되어 시스템 크기 2배
3. 중복에서 불일치가 생긴다 - A에서 고쳤는데 B에서는 안고쳐서 버그
4. 복잡성 자체가 버그를 만든다 - 얽힌 코드에서 예상 못한 상호작용
5. 테스트 비용이 증가한다 - 큰 덩어리를 테스트하려면 셋업이 복잡해짐
(음 이거 완전 우리 레거시 이야긴데)
프로덕트가 성장할수록 비용과 좌절이 기하급수적으로 증가한다.
이 13장에서는 전체적으로 clean한 클래스 설계에 대해 이야기할 것이다.
그런데, 이 clean(깨끗한)의 정의가 중요하다.
'깨끗한'은 비난이 아니다.
'깨끗하지 않은'은 평범한 개발자가 이해하거나 유지보수하는 데 많은 노력을 요구하는 코드를 특성짓는 방법이다.
'코드가 더럽다'는게 아니라, '코드는 다음 사람이 읽을 때 더 힘들다'라는 객관적 관찰
사람이 아니라 코드의 특성을 이야기하는 것
Classes provide ways to help you keep your sanity as your system grows.
클래스는 당신의 시스템이 성장할 때 제정신을 유지하는 데 도움을 줄 것이라 함..ㅋ
Characterizing Class Design
설계의 품질은 변화에 직면했을 때만 진정으로 평가할 수 있다
코드가 아무리 예뻐도 새 기능을 추가할 때 고통스러우면 나쁜 설계이다.
반대로 못생겨도 변경이 쉬우면 좋은 설계이다.
저자는 서브 루틴의 역사까지 거슬러 올라갔는데,
1940년 후반 폰 노이만과 골드 스타인의 논문에서 서브루틴 개념이 시작됐고,
1951년 EDSAC 컴퓨터에서 실제로 구현됐다고 한다.
핵심은 코드 모듈화가 소프트웨어 개발 비용을 줄인다는 믿음이 70년 넘게 이어져왔다는 것!
Heuristics and Characteristics
그리고 이 모듈화 경험에서 나온 게 다양한 휴리스틱과 특성이다.
긍정적 휴리스틱 - 이렇게 하라
1. 긍정적 휴리스틱 - 켄트 벡의 창발적 설계 4규칙
- 모든 코드가 테스트 가능하도록 보장하라
- 논리적 중복을 제거하라
- 모든 요소에 명확하고 간결한 이름을 부여하라
- 요소의 수를 최소화하라
부정적 휴리스틱 - 이러지 마라!
- 기존 코드 복붙한 다음 변경해서 새 로직 만드는 습관
- 저자가 안티 패턴의 별명을 나열했는데:
grab and stab(잡아서 찌르기), snatch and patch(낚아서 땜빵하기), copy and corrupt(복사해서 오염시키기)
긍정적 특성 - SOLID
- Bob Martin의 SOLID 원칙은 약 30년간 검증을 견대냈고, 함수형 코드에도 적용 가능하다
부정적 특성 - Code Smells
- 냄시나는 코드... 코드에서 피해야 할 징후들
- shotgun surgery(산탄총 수술): 간단한 변경 하나 하려고 수많은 클래스를 업데이트 해야 하는 상황

이런 것들을 통틀어 설계 관점(design perspective)이라고 부른다
결국 핵심은?
작고 응집력있는 모듈과 함수를 만드라는 뜻
하지만, 저자가 강조하는 건 '균형'이다.
어떤 원칙도 절대적이지 않다.
켄트 벡의 4번재 규칙 '요소의 수를 최소화하라'라는 말이 있듯
이점도 없는 너무 작은 클래스를 만드는 것도 과한 일이다.
하지만, 대부분의 시스템은... 크고 뒤죽박죽이고 다목적 모듈과 함수로 가득 차있다.
(가득 찬 건 내 눈물이다...)
소프트웨어의 모든 선택에는 트레이드 오프가 있다는 점을 기억하면서,
마음에 드는 설계 관점을 선택하고, 유지보수하기 쉬운 코드를 만드는 결과에 집중하자
When Is a Class Too Large?
도서관 시스템의 'HoldingService' 클래스를 살펴보자.
소장 자료를 추가하고, 빌리고, 반납하고, 이관하는 기능이 모여있다.
얼핏 보면 핵심 책임이 '소장 자료의 배치 관리'로 하나인 것 같지만
SRP는 좀 더 까다롭게 본다.
SRP를 준수하는 클래스는 변경할 이유가 하나뿐이어야 한다.
단일 책임 클래스가 좋은 이유는
- 이름이 내부 동작을 간결하게 반영 -> 찾기 쉬움
- 재사용 가능성 up
- OCP 준수로 미래 변경에 닫혀있음
- 테스트 하기 쉬움
- 시스템이 더 유연해짐
언뜻 보면 하나처럼 보이는 HoldingService의 각 기능는 각기 다른 정책(policy)을 구현하고 있다.
이 정책들이 독립적으로 변경될 수 있다면, 그건 각 정책을 별도의 클래스로 구현해야 한다는 신호이다.
SRP 기준이 까다롭다곤 하지만, 변경의 중심을 추측하라고 하진 않았다.
변경할 코드를 나서기 보단, 다음 변경 요구를 기다리고, 그 기회를 활용해 시스템을 더 준수하는 방향으로 형성해야 한다.
Policies in Code
도서관 대출 시스템의 핵심인 반납/대출이 변동될 가능성이 거의 없다고 하자.
그래도, HoldingService가 변경될 수 있는 이유는 언제든 생겨날 수 있다.
Where Reasons to Change Hide
예를 들어 'DVD 대여 기간을 7일에서 14일로 늘리고 싶다'는 요구사항이 있다고 치자
반납 기한 계산을 Holding 클래스에 위임하고 있어서 DVD 대여 기간 변경은 HoldingServcie에 영향을 주지 않는다.
하지만, checkIn 메서드에는 문제가 있다.
그 내부에 '반납 기한 이후 반납 시, 연체다'라는 규칙이 있다.
(오우 이 문장 보고 서울대 도서관에서 빌린 책 반납기한 연장함 마틴 아저씨 땡큐!)
근데 이 정책이 복잡해질 수 있다. -> VIP는 벌금 면제, 유예 기간 추가 등
결국 이 규칙 한 줄이 HoldingService가 변경되어야 하는 또 다른 이유를 나타내는 셈이다.
또, 구현 세부사항을 직접 연출함으로서(추상화가 안 됨) 코드를 읽기 불편하게 만든다
Fixing the Problem
1. Extract Method
- '연체인가'라는 개념을 추상화한다.
- 10장에서 배운 것! Extract till you drop! 더 이상 추출할 수 없을 때까지 추출하라!
https://developer-dreamer.tistory.com/209
- 명확하고 간결한 메서드 이름은 주석의 필요를 없앤다.
- 1~5줄의 코드를 안내하기 위해 주석이 필요하다면, 그 자체를 메서드로 추출하는 것을 고려해볼 것!
- 특히 서술어(predicate)를 사용해 복잡한 메서드를 추출하면 코드 이해도를 높일 수 있다
if (x(a) && y || !z(c, d)) 이런 날 것의 조건문을 'isLate' 같은 서술어로 바꾸는 것
2. Move Method
- feature envy - 이 표현 번역하기 정말 애매하다...
1번에서 메서드를 분리하고 나면,
정작 자신이 몸 담고 있던 HoldingService 클래스가 아니라 Holding 클래스에 여러 질문을 던지는 것을 볼 수 있다.
반납한 날짜가 뭐야? 반납 기한이 뭐야? 이걸 envy라고 표현한 것 같다.
HoldingService 안에 있을 땐 몰랐지만, 분리하고 나니 이 매서드는 사실 Holding 클래스에 있는 게 맞았던 것
어떻게 보면 변경사항을 다른 클래스로 떠넘겼다고 볼 수 있지만,
SRP 관점에서 변경 이유를 줄이도록 적절한 위치로 이동시킨 것이라고 말한다.
매 변경마다 이런 continous design(지속적인 설계)의 일환으로 이런 질문을 계속해야 한다고 말한다
An Overly Open Implementation
아까 내부에서 메서드를 분리해냈던 checkIn 메서드에 또 다른 코드도 말썽이다.
feature envy 양상을 보여서 calculateLateFine을 Holding 클래스로 옮겨본다.
저자가 제일 싫어하는 switch문이 만들어졌다....
실수로 한 case에서 다른 case로 흘러내릴 수 있는 구식 switch가...
calculateLateFine 메서드는 시간이 지나면 많은 변경을 겪는 유형이다.
1. 새로운 자료 유형 추가 (전자책, 퍼즐 등)
2. 새로운 벌금 방식 도입
3. 자료 가격 인상 반영
이건 OCP(개방-폐쇄 원칙) 위반이다.
변경을 위해 기존 클래스를 '여는' 것을 최소화하고, 대신 단일 목적 클래스를 추가해야 한다.
Sholud We Do Anything Now?
전형적인 시스템이 그렇듯, 사실상 어떤 클래스도 닫혀있지 않고 (OCP 활용 기회를 놓침)
코드를 건드려야 하는 모든 사람에게 변경 환영(^~^) 상태가 됨
최선은 just wait!
다음 변경이 올 때까지 기다리자.
다음을 예측하며 추측 정리하는 것은 불필요한 위험을 야기한다.
(하는김에이렇게저렇게금지)
What About Now?
이제 새로운 변경 사항이 찾아왔다! (지금이니? 지금이야!)
직소 퍼즐과 보드 게임을 빌릴 수 있도록 새로운 자료 유형을 추가해야 한다.
새 요구사항을 위해 먼저 코드를 리팩토링해서 변경 작업이 쉽게 진행될 수 있도록 한다.
switch의 각 분기를 Strategy 클래스로 추출한다.
그리고 Materialtype enum에 Strategy 객체를 직접 넣는다.
-> Holding의 calculateLateFine이 한 줄로 단순화된다.
Closed, Cohesive, Single-Responsibility Classes
새로 추가된 직소 퍼즐과 보드 게임에 대해 도서관 위원회가 새로운 벌금 방식을 시험해보기로 했다.
테스트 대상에 해당하는 Strategy 클래스를 테스트 주도로 작성한다.
이제 MaterialType에 클래스 한 줄만 추가하면 된다.
기존 클래스 수정 거의 없이 새 기능 추가 완료! OCP의 위력이다.
MaterialType enum을 데이터베이스에서 읽어오는 클래스로 교체하면
완전한 OCP가 가능하다고 한다.
새 클래스를 코딩하고, DB에 충분한 구성 데이터를 넣고, 배포하면 된다.
기존 클래스에 대한 변경은 필요없다.
When Policies Change
많은 서비스 클래스는 수많은 서로 섞이기 어려운 동작을 섞이도록 오케스트레이션 해야 한다.
다양한 도메인(소장 자료, 이용자)에 관한 비즈니스 로직과 상호작용하고,
데이터를 저장하거나 검색할 수 있고,
외부 서비스와 상호작용할 수 있다.
잘 정의된 SRP 준수 서비스는 이를 따라야 한다.
- 정책을 선언하고 구현 세부 사항을 다른 클래스에 위임하는 오케스트레이션 로직만 포함한다.
- 관련된 도메인이나 유틸리티 동작에 대한 구현 세부사항만 포함한다.
Don’t mix policy with implementation detail.
정책과 구현 세부사항을 섞지 마라.
이해하고, 탐색하고, 유지보수하는 데 비용이 더 든다.
정책 변경은 코드 변경의 한 가지 이유고, 정책의 한 단계에 대한 구현 세부 사항은 또 다른 이유이다.
그니까, 이 둘을 같이 두는 건 SRP 위반이기도 하다.
Is This Overengineering?
SRP와 OCP를 극단으로 밀어붙이면 어떻게 될까?
모든 라우트마다 별도 클래스, 모든 조건문이 다형적으로 구현, 정책의 각 단계도 별도 클래스...
이런 시스템은 진정으로 OCP를 지원해서,
모든 새 동작이 새 클래스를 제자리에 놓는 것으로 달성된다.
모든 클래스가 작고 격리되어 쉽게 테스트된다.
결론적으로, SRP와 OCP는 이상으로 간주하라.
항상 그 방향으로 움직이되, 도달하지 못해도 괜찮다.
하지만 그 반대 방향으로 움직이면서 점점 더 큰 모놀리스 클래스를 만드는 건 안된다.
지금은 시스템의 결함을 용서하라.
앞으로는 만드는 각 변경을 평가하라.
변경을 위해 몇 개의 기존 클래스를 '열어'야 했는가?
(용서가 안되면 어떡하죠?;; 하아...)
Simpler Testing
HoldingService 테스트를 유지하면서 벌금 관련 테스트를 추가할 수도 있다.
하지만 개별 Strategy 클래스에 집중된 unit test를 만드는 게 더 낫다.
Why?
- 격리되고 폐쇄적인 개념이라 테스트하기 쉽다.
- 클래스의 모든 의도된 동작을 문서화한다
- 테스트가 통과하는 한 신뢰할 수 있는 문서 역할을 한다.
저자가 DegradingFineStrategy의 테스트를 TDD로 20분도 안걸려서 만들었다고 한다.
'기존 클래스 테스트를 건드릴 필요가 전혀 없었다'
다만 주의할 점!
작고 단일 목적의 클래스로 추출했지만, 다른 맥락에서 유용하다고 보지 않으면 공개적으로 접근할 수 없게 만들어라.
상위 레벨에서 테스트해서 간접적으로 커버하는 게 낫다.
구현 세부 사항을 테스트하는 게 아니라,
작은 동작적 개념의 결과를 테스트하는 것이다!
Enter AI
인간은 지난 90년 간 5-10년 주기로 기술적으로 도약 점프 발전을 해왔다.
AI가 등장하면서 이 도약 점프 갭이 엄청 커졌고, 2040년대까지 이 특이점을 향해 가속할 것이다.
우리는 이제 LLM에게 클래스 수준에서 코드를 생산하라고 요청할 수 있다.
아마 80%는 좋은 코드일 거다. 8:2 법칙에 따라..
LLM이 더 좋은 코드를 짜도록 돕는 방법은
1. 예제를 제공한다.
2. 스타일을 제공한다.
- 작고 단일 목적의 함수/메서드를 생산한다.
- 상태관리와 side effect이 적은 더 함수적인 솔루션을 생산한다.
- 명확성을 강조하는 간단한 스타일을 제공한다.
이 방향은 우리 인간이 줄곧 지향하라고 외쳐왔던 코딩 스타일과도 일치한다!
(그리고 내가 최근에 짠 AI Rule과도 일치한다! 만세!)
It Will Be Wrong
Unfortunately... LLM의 나머지 20% 코드는 결함이 있을 것이다.
그래서 동작 의도에 대한 포괄적 테스트는 AI를 사용할 때 필수적이다.
현재 AI를 줄 단위 코딩 보조로 쓰고 있지만,
이미 모듈 수준에서 코드를 생산하게 하는 것이 더 효과적인 지점에 왔다.
이 시점에서 내부 모듈 코드 내용은 알빠노!가 된다.
결국 우리의 시선은 시스템의 전체 아키텍쳐/설계에 관심을 두게 된다.
OCP와 SRP에 기반한 시스템을 만들고, AI로 적절한 모듈을 생성하고, 테스트를 검증하고, 제자리에 놓는다.
시스템 설계가 다시 중심이 된다.
검증된 디자인 패턴이 다시 한 번 빛난다
함수형 파이프라인(Functional Pipeline)
커맨드(Command)
팩토리(Factory)
데코레이터(Decorator)
전략(Strategy)
컴포지트(Composite)
책임 연쇄(Chain of Responsibility)
브리지(Bridge).
깨끗한 코드는 우리 인간의 가까운 미래에 여전히 중요하다.
어느 시점이 되면 AI는 예제/테스트 집합으로부터 전체 시스템을 완전히 구현할 수 있게 될 것이다.
We’ll be happy to have retired by then.
(이아저씨가사람을마음대로은퇴시키네???저이제곧1년차되는데저기요)
아무튼 우리에게는 여전히 기회가 있다(고 한다. 진짜지..?)
AI가 구현한 조각들의 오케스트레이션으로서 시스템을 설계하고 제공하는 방법을 아는 사람으로서의 기회가 있을 것이다.
이 AI 문단이 클린 코드를 읽으며 가장 공감되는 문단이군요.
1-13장 마지막 부분을 복사해서 전사에 뿌리고 싶네요.
(???: 안사요)
그리고 이랑 비슷한 논조의 긱뉴스 글도 같이 읽어보면 좋을 듯
코드를 읽지 않는 시대, 엔지니어는 무엇을 읽어야 하는가
https://news.hada.io/topic?id=26874
코드를 읽지 않는 시대, 엔지니어는 무엇을 읽어야 하는가 | GeekNews
AI를 쓰면 학습이 줄어든다?Anthropic 연구: AI로 코딩 과제를 완료한 개발자들의 퀴즈 점수가 17% 낮았다핵심은 "AI를 쓰면 학습이 줄어든다"가 아니라, 같은 AI를 쓰면서도 사용 방식에 따라 결과가
news.hada.io
어휴 13장 정리하는데 진짜 오래 걸림
작성: 2026.02.13. 23:37
'개발자 강화 > 개발 독서' 카테고리의 다른 글
| [Clean Code 2판] 1-15: Clean Tests (0) | 2026.03.06 |
|---|---|
| [Clean Code 2판] 1-14: Testing Disciplines (0) | 2026.02.25 |
| [Clean Code 2판] 1-12: Objects and Data Structures (1) | 2026.02.04 |
| [Clean Code 2판] 1-11: Be Polite (0) | 2026.02.02 |
| [Clean Code 2판] 1-10: One Thing (0) | 2026.01.25 |