클린 코드 실전 강의 교재¶
17장 — 냄새와 휴리스틱¶
대상: Java/Spring 백엔드 입문~중급 수강생 형식: 휴리스틱 카탈로그 — 사전처럼 사용 전제 환경: Java 17+, Spring Boot 3.x
0. 이 장을 시작하기 전에¶
0.1 학습 목표¶
- 66개 휴리스틱 의 의미를 한 줄씩 익힌다.
- 코드 리뷰 어휘 (
G19,N1,T5...) 로 합의 빨라짐. - 정련 시 사전처럼 펼친다.
0.2 큰 그림 — 7 카테고리¶
C Comments (5) — 주석 관련
E Environment (2) — 빌드·테스트 환경
F Functions (4) — 함수 관련
G General (36) — 일반 ★ 가장 큼
J Java (3) — 자바 특화
N Names (7) — 이름
T Tests (9) — 테스트
비유 — 17장은 "주방의 점검 체크리스트"입니다.
손님이 받기 전 66개 항목 점검 — 모든 항목을 매번 외울 필요 없지만, 사전으로 펼쳐 보면 안전.
0.3 현업에서 왜 중요한가¶
- PR 리뷰 어휘로 즉시 활용 — "G23 적용 검토" 한 줄로 합의.
- 정련 시 사전 — 모르는 휴리스틱 발견 → 검색 → 적용.
17.1 주석 (Comments) — C1~C5¶
C1: 부적절한 정보¶
저자·수정 이력·SCM 관련 메타 — 주석이 아니라 SCM에.
C2: 쓸모 없는 주석¶
오래된·관련 없는·잘못된 주석은 즉시 삭제.
C3: 중복된 주석¶
코드가 이미 말하는 걸 다시 말함. i++; // i를 증가 — 잡음.
C4: 성의 없는 주석¶
문장 다듬어 적어라. 한 단어보다 한 문장이, 한 문장보다 잘 다듬은 문단이 낫다.
C5: 주석 처리된 코드¶
즉시 삭제. Git 이 기억.
17.2 환경 (Environment) — E1~E2¶
E1: 여러 단계로 빌드해야 한다¶
git clone 후 한 명령으로 빌드 가능해야. ./gradlew build / npm install && npm test.
E2: 여러 단계로 테스트해야 한다¶
한 명령 (또는 IDE 한 클릭) 으로 모든 테스트.
17.3 함수 (Functions) — F1~F4¶
F1: 너무 많은 인수¶
이상적 0, 1~2 OK, 3 신중, 4+ 정당화. → 인수 객체 (entity-refactoring 6.8).
F2: 출력 인수¶
매개변수로 출력 X. 반환값 또는 객체 자체 변경 (Tell, Don't Ask).
F3: 플래그 인수¶
boolean 인수는 함수가 두 가지 일을 한다는 신호. 분리.
F4: 죽은 함수¶
호출되지 않는 함수 즉시 삭제. Git 기억.
17.4 일반 (General) — G1~G36¶
가장 큰 카테고리. 카탈로그 형식으로 한 줄씩.
| 코드 | 한 줄 |
|---|---|
| G1 | 한 소스 파일에 여러 언어 — 분리 |
| G2 | 당연한 동작 누락 — 사용자가 기대하는 기본 동작은 구현 |
| G3 | 경계 조건 처리 미흡 — 0·1·MAX·null·빈 컬렉션 점검 |
| G4 | 안전 절차 무시 — 컴파일 경고·테스트 비활성 금지 |
| G5 | 중복 — DRY, 가장 흔한 악 |
| G6 | 추상화 수준 부적절 — 한 클래스에 다른 수준이 섞임 |
| G7 | 기초 클래스가 파생에 의존 — OO 위배 |
| G8 | 과도한 정보 — 클래스가 너무 많이 노출 |
| G9 | 죽은 코드 — 즉시 삭제 |
| G10 | 수직 분리 — 변수/함수가 사용처 근처 |
| G11 | 일관성 부족 — 한 개념엔 한 용어 |
| G12 | 잡동사니 — 빈 생성자·사용 안 하는 변수 |
| G13 | 인위적 결합 — 무관한 클래스가 같이 변함 |
| G14 | 기능 욕심 — 다른 클래스 데이터를 더 씀 (8.1 함수 옮기기) |
| G15 | 선택자 인수 — boolean 플래그 (F3 와 짝) |
| G16 | 모호한 의도 — 이름·구조가 의도 못 드러냄 |
| G17 | 잘못 지운 책임 — SRP 위배 |
| G18 | 부적절한 static — 다형성 가능성 닫힘 |
| G19 | 서술적 변수 — 복잡한 식은 변수로 (entity-refactoring 6.3) ⭐ |
| G20 | 이름과 기능 일치 — getDay() 가 Date.getYear() 호출하면 X |
| G21 | 알고리즘 이해 — 직관 X, 검증된 동작만 |
| G22 | 논리적 의존성 물리화 — assert·검증으로 명시 |
| G23 | If/Else·Switch보다 다형성 ⭐ |
| G24 | 표준 표기법 — 팀 컨벤션 |
| G25 | 매직 숫자 → 상수 ⭐ |
| G26 | 정확하라 — "거의" 가 아니라 정확히 |
| G27 | 관례보다 구조 — switch 보다 다형성 |
| G28 | 조건 캡슐화 — if (shouldBeDeleted(x)) 가 if (x.timer.expired() && !x.locked) 보다 명확 |
| G29 | 부정 조건 피하기 — if (isReady) 가 if (!isNotReady) 보다 명확 |
| G30 | 함수는 한 가지만 ⭐ (3장) |
| G31 | 숨겨진 시간적 결합 — 호출 순서 의존이면 매개변수로 강제 |
| G32 | 일관성 유지 — 같은 일은 같은 방식 |
| G33 | 경계 조건 캡슐화 — if (level + 1 < tags.size()) 보다 if (nextLevelExists) |
| G34 | 함수는 추상화 수준 한 단계만 내려가기 ⭐ |
| G35 | 설정 정보 최상위 — main 또는 config |
| G36 | 추이적 탐색 피하기 — 디미터 법칙 (6장) |
17.5 자바 (Java) — J1~J3¶
J1: 긴 import 회피 — 와일드카드 사용¶
J2: 상수는 상속하지 않는다¶
상수 인터페이스 안티패턴 — 상수는 enum 또는 유틸 클래스.
J3: 상수 vs Enum¶
값 집합은 enum — Effective Java Item 34 와 동일.
17.6 이름 (Names) — N1~N7¶
N1: 서술적 이름 ⭐¶
이름이 책임을 드러나게. 모호한 이름 (x, data, info) 회피.
N2: 적절한 추상화 수준 — 이름은 구현 X, 의도 O¶
getProcessedRecords() 가 getRecords() 보다 명확.
N3: 표준 명명 — findBy*, is*, to* ...¶
N4: 명확한 이름¶
긴 이름이라도 모호한 짧은 이름보다 낫다.
N5: 긴 범위는 긴 이름¶
지역 변수 i 는 OK, 멤버 변수 i 는 X.
N6: 인코딩 회피 — 헝가리식 표기 (strName, mName) X¶
N7: 이름으로 부수 효과 설명¶
createUserAndSendEmail() — 두 일을 한다는 신호 + 분리 검토.
17.7 테스트 (Tests) — T1~T9¶
T1: 불충분한 테스트¶
핵심 비즈니스 + 과거 사고 부위는 100% 가까이.
T2: 커버리지 도구 사용¶
JaCoCo·Istanbul — 빠진 부분 가시화.
T3: 사소한 테스트도 건너뛰지 마라¶
쉬워 보이는 코드도 테스트하면 (1) 의도 박제, (2) 미래 변경 안전망.
T4: 무시한 테스트는 모호함의 신호¶
@Disabled 가 쌓이면 모호한 요구사항의 증거. 빨강이 더 정직.
T5: 경계 조건 테스트 ⭐¶
0·1·MAX·MIN·null·빈 컬렉션·시간 경계 (자정·연말).
T6: 버그 주변은 철저히¶
버그 1개 = 주변에 더 있을 가능성. 발견 시 더 깊이 테스트.
T7: 실패 패턴을 살펴라¶
연관된 실패들이 패턴을 만들면 → 공통 원인.
T8: 테스트 커버리지 패턴¶
같은 부위가 자주 빠지면 → 그 부위 설계 문제.
T9: 테스트는 빨라야 한다 (F.I.R.S.T. 의 F)¶
핵심 교훈¶
- 66개 다 외울 필요 X — 사전처럼 펼쳐 사용.
- ⭐ 표시 핵심 8개 (G19·G23·G25·G30·G34·N1·T5·F1) 만 익혀도 80% 효과.
- 카테고리 코드 (C·E·F·G·J·N·T) = 리뷰 어휘.
- 14~16장의 점진 정련에 이 사전이 도구.
함정 / 주의¶
- 17장을 도그마로 들면 "코드가 G로 시작하는 어떤 항목에 걸리네" 같은 형식주의 위험.
- 우선순위 — 1·2·3·4장 (마인드셋·이름·함수·주석) 이 17장보다 먼저.
체크리스트 (코드 리뷰용 표준 어휘)¶
PR 코멘트 예시: - "이 부분 G19 검토 — 복잡한 식을 서술적 변수로" - "G23 — switch 가 두 곳 이상, 다형성 검토" - "N1 — 변수명이 의도 못 드러냄" - "T5 — 경계 조건 (빈 컬렉션) 테스트 추가"
퀴즈¶
Q1. 17장 66개 휴리스틱을 어떻게 활용?
A. 사전처럼 펼쳐 보기. 외우는 게 아니라, 정련 시 모르는 항목 발견 → 검색 → 적용. 코드 리뷰 어휘 (G19·N1) 로 합의 빨라짐.
Q2. ⭐ 휴리스틱 8개의 공통점?
A. 이름·함수 추출·매직 숫자·다형성·서술적 변수·경계 조건 — 매일 마주치는 코드의 가장 흔한 개선 후보. 가성비 압도적.
Q3. G23 (If/Else·Switch 보다 다형성) 이 OOP 핵심인 이유?
A. 새 타입 추가 = 새 클래스 1개. switch 모든 위치 수정 안 함 (산탄총 수술 회피). OCP 충족. entity-refactoring 10.4·오브젝트 12장·Effective Java Item 34 와 같은 결.
Q4. T4 (무시한 테스트는 모호함의 신호) 의 의미?
A. @Disabled 가 쌓이는 건 요구사항이 불명확 하다는 증거. 빨강 상태 그대로 두는 게 차라리 정직 — 무엇을 해결해야 하는지 보임.
Q5. 17장이 1~16장의 결론 카탈로그라 불리는 이유?
A. 책 전체의 권고가 66개 휴리스틱으로 환원. 1~13장이 각 영역의 원리, 17장이 그 원리의 실천 사전. 14~16장이 그 사전을 적용하는 사례.
책 전체 마치며 — 17장 + 4규칙 + 보이스카우트¶
Clean Code 의 압축¶
- 4규칙 (12장) — 모든 테스트 통과 / 중복 없음 / 의도 표현 / 최소
- 66 휴리스틱 (17장) — 매일의 정련 사전
- 보이스카우트 규칙 (1장) — 매 PR 작은 개선
책 전체 → 4권 도서 비교 (entity-clean-code)¶
| 책 | 단위 | 시점 |
|---|---|---|
| 오브젝트 | 객체·협력 | 처음부터 잘 설계 |
| Effective Java | 메서드·필드 | 매번 짤 때 |
| 리팩터링 | 1단계 변환 | 이미 짠 코드 |
| Clean Code | 줄·이름·함수 | 매 라인 |
다음 단계¶
- Clean Architecture (Uncle Bob) — 시스템 단위
- The Clean Coder (Uncle Bob) — 태도·전문성
- 본 위키의 entity-effective-java / entity-refactoring / entity-object 교차 학습
강의 교재 17장 완료. 4권 도서 비교의 마지막 책 정련까지 완성.