콘텐츠로 이동

클린 코드 실전 강의 교재

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 회피 — 와일드카드 사용

import java.util.*;   // 권장 (책 시점, IntelliJ 자동으로 풀기도)

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)


핵심 교훈

  1. 66개 다 외울 필요 X — 사전처럼 펼쳐 사용.
  2. ⭐ 표시 핵심 8개 (G19·G23·G25·G30·G34·N1·T5·F1) 만 익혀도 80% 효과.
  3. 카테고리 코드 (C·E·F·G·J·N·T) = 리뷰 어휘.
  4. 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 줄·이름·함수 매 라인

다음 단계

강의 교재 17장 완료. 4권 도서 비교의 마지막 책 정련까지 완성.