IT/책

[Clean Code] 17장, 냄새와 휴리스틱

Terriermon 2021. 11. 21. 23:01

Clean Code

17장, 냄새와 휴리스틱

 

 

 

주석

C1: 부적절한 정보

- 다른 시스템에 저장할 정보는 주석으로 적절하지 못함

ex) 소스코드 관리 시스템, 버그 추적 시스템, 이슈 추적 시스템 등

 

- 변경 이력과 장황한 날짜는 소스 코드를 번잡하게 만듦

 

- 작성자, 최종 수정일, SPR 번호등만 주석으로 삽입

 

 

C2: 쓸모 없는 주석

- 오래된 주석, 엉뚱한 주석, 잘못된 주석 들은 빠르게 삭제

 

 

C3: 중복된 주석

- 설명하는 주석 주의

ex) i++ // i 증가

 

 

C4: 성의 없는 주석

- 작성 할 가치가 있으면 간결하고 명료하게 작성

 

 

C5: 주석 처리된 코드

- 주석 처리된 코드는 즉각 지워버려야 함

 

 

 

환경

E1: 여러 단계로 빌드

- 빌드는 간단히 한 단계로 끝나야 함

 

- 소스코드 관리 시스템에서 이것저것 따로 체크아웃 ❌

 

- 한 명령으로 전체를 체크하여 빌드

 

 

E2: 여러 단계로 테스트

- 모든 단위 테스트는 한 명령으로 돌려야 함

 

- 테스트는 빠르고 쉽고 명백해야 함

 

 

 

함수

F1: 너무 많은 인수

- 함수에서 인수 개수는 작을 수록 좋음

 

 

F2: 출력 인수

- 직관을 정면으로 위배

 

- 함수에서 상태를 변경해야 하면 객체의 상태를 변경하여야 함

 

 

F3: 플래그 인수

- boolean은 함수가 여러 기능을 수행한다는 증거

 

 

F4: 죽은 함수

- 아무도 호출하지 않는 함수는 삭제

 

 

 

일반

G1: 한 소스 파일에 여러 언어 사용

- 혼란스럽고 조잡한 경우가 많음

 

- 하나의 소스 파일에는 하나의 언어만 사용

 

 

G2: 당연한 동작 구현❌

- 최소 놀람의 원칙에 의거해 함수나 클래스는 다른 프로그래머가 당연하게 여길 동작과 기능 제공

ex) Day day = DayDate.StringToDay(String dayNanme); 에서, Monday는 Day.MONDAY, Day.MON, Day.mon 등 올바로 변환하는 것을 기대함

 

 

G3: 경계를 올바로 처리하지 않음

 

 

G4: 안전 절차 무시

- 컴파일러 경고를 무시하지 말아야 한다

 

 

G5: 중복

중복을 제거하는 것이 가장 핵심

- DRY(Don't Repeat Yourself) 원칙

 

- 코드에서 중복을 발견할 때, 추상화할 기회로 간주

 

- 중복된 코드를 하위 루틴이나 다른 클래스로 분리

 

- switch/case나 if/else는 다형성으로 대체

 

- 알고리즘이 유사하나 서로 코드가 다른 중복 > TEMPLATE METHOD 패턴이나 STRATEGY 패턴으로 중복 제거

 

 

G6: 추상화 수준이 올바르지 못함

- 모든 저차원의 개념은 파생 클래스에 넣고, 고차원의 개념은 추상 클래스에 넣음

ex) 세부 구현과 관련된 상수, 변수, 유틸리티 함수는 기초 클래스에 넣으면 안됨

 

- 기초클래스/파생 클래스, 소스파일/모듈/컴포넌트로 분리

 

 

G7: 기초 클래스가 파생 클래스에 의존하는 경우

- 고차원 기초 클래스 개념을 저차원 파생 클래스 개념으로부터 분리해 독립성을 보장하기 위함

> 기초 클래스는 파생 클래스를 아에 몰라야 함

 

 

G8: 과도한 정보

- 잘 정의된 모듈은 인터페이스가 아주 작음

 

- 자료, 유틸리티 함수, 상수, 임시변수를 모두 숨겨야 함

 

 

G9: 죽은 코드

- 불가능한 조건을 확인하는 if, thorw문이 없는 try/catch 블록, 아무도 호출하지 않는 유틸리티 함수, switch/case문에서 불가능한 case 조건 등

 

- 죽은 코드는 설계가 변해도 제대로 수행되지 않음

 

 

G10: 수직 분리

- 변수와 함수는 사용되는 위치에 가깝게 정의

 

- 지역 변수: 처음 사용하기 직전에 선언, 수직으로 가깝게 위치

 

- 비공개 함수는 호출한 직후 바로 정의

 

 

G11: 일관성 부족

- 유사한 개념은 같은 방식으로 구현

 

 

G12: 잡동사니

- 비어있는 기본 생성자, 아무도 사용하지 않는 변수, 아무도 호출하지 않는 함수, 정보를 제공하지 못하느 주석 등 제거

 

 

G13: 인위적 결합

- 서로 무관한 개념을 인위적으로 결합X

ex) enum, static: 특정 클래스에 속할 이유가 없음

 

- 인위적인 결합은 직접적인 상호작용 없는 두 모듈 사이에서 일어남

 

 

G14: 기능 욕심

- 메서드가 다른 객체의 참조자와 변경자를 사용해 그 객체 내용을 조작하지 않아야 함

 

 

G15: 선택자 인수

- 선택자 인수(bool)는 목적을 기억하기 어렵고, 여러 함수를 하나로 조합함

 

 

G16: 모호한 의도

- 코드를 짤 때는 의도를 분명하게 밝혀야 함

ex) 행을 바꾸지 않고 표현한 수식, 헝가리식 표기법, 매직 번호 등

 

 

G17: 잘못 지운 책임

- 코드를 배치하는 위치 -> 최소 놀람 원칙 적용

 

 

G18: 부적절한 static 함수

- 특정 인스턴스와 관련 없이 모두 사용한 경우 사용

 

- 일반적으로 인스턴스 함수가 static 함수보다 더 좋음

 

 

G19: 서술적 변수

- 서술적 변수 이름을 사용하면 해독하기 어려운 모듈이 쉽게 읽힘

 

 

G20: 이름과 기능이 일치하는 함수

Date newDate = date.add(5);

- 함수 이름이 모호함

 

- addDaysTo 또는 increaseByDays로 변경하여 명확하게 해야 함

 

 

G21: 알고리즘을 이해하라

- 기능이 뻔히 보일 정도로 함수를 깔끔하고 명확하게 재구성

 

 

G22: 논리적 의존성은 물리적으로 드러내라

- 한 모듈이 다른 모듈에 의존한다면 물리적인 의존성도 있어야 함

 

 

G23: If/Else나 Switch/Case 대신 다형성을 사용

 

 

G24: 표준 표기법

- 표준을 설명하는 문서는 코드 자체로 충분해야 하며 별도 문서를 만들 필요가 없어야 함

 

 

G25: 매직 숫자는 명명된 상수로 교체

- 코드에서 숫자를 사용하지 말라

ex) SECONDS_PER_DAY = 60;

 

G26: 정확하라

- 검색 결과 중 첫 번째 결과만 유일한 결과로 간주하지 말아라

 

- 조회 결과가 하나 뿐이면 하나인지 확실하게 해야함

 

 

G27: 관례보다 구조를 사용

- 설계 결정 시, 규칙보다 관계를 사용

 

 

G28: 조건을 캡슐화

if(shouldBeDeleted(timer))

if(timer.hasExpired() && !timer.isRecurrent())

- 위의 조건문이 더 좋음

 

 

G29:부정 조건은 피해라

 

 

G30: 함수는 한 가지만 해야 함

- 여러 개로 나누기

 

G31: 숨겨진 시간적 결합

- 시간적 결합은 숨기면 안됨

 

- 함수 인수를 적절히 배치하여 함수가 호출되는 순서를 명백하게 나타내야 함

 

 

G32: 일관성 유지

- 구조에 일관성이 없으면 바꿔도 된다고 생각함

 

 

G33: 경계 조건 캡슐화

 

 

G34: 함수는 추상화 수준을 한 단계만 내려가야 함

- 함수 내 모든 문장은 추상화 수준이 동일해야 함

> 함수 이름이 의미하는 작업보다 한 단계 낮아야 함

 

- 함수에서 추상화 수준을 분리하면 앞서 드러나지 않았던 새로운 추상화 수준이 드러나는 경우가 많음

 

 

G35: 설정 정보는 최상위 단계에 둬라

 

 

G36: 추이적 탐색을 피하라

- 디미터의 법칙: A가 B를 사용하고 B가 C를 사용해도 A가 C를 알아야 할 필요가 없음

> 자신이 직접 사용하는 모듈만 알아야 함

 

 

 

자바

J1: 긴 import 목록을 피하고 와일드 카드를 사용

ex) import package.*;

- 명시적인 import 문은 강한 의존성을 생성하지만, 와일드카드는 그러지 않음

 

 

J2: 상수는 상속하지 않음

- import static package.*;를 통해 언어의 범위 규칙을 속이는 행위

 

 

J3: 상수 대 Enum

- int보다 유연하고 서술적으로 강력한 도구

 

 

이름

N1: 서술적인 이름을 사용하라

- 소프트웨어 가독성의 90%는 이름으로 결정함

 

 

N2: 적절한 추상화 수준에서 이름을 선택

- 구현을 드러내는 이름 사용❌

 

 

N3: 가능하다면 표준 명명법 사용

- 프로젝트에 유효한 이름의미가 담길 수록 독자가 코드를 이해하기 쉬움

 

 

N4: 명확한 이름

- 길지만 모듈에서 한 번만 호출되면서 단점을 메꿈

 

 

N5: 긴 범위는 긴 이름을 사용

- 이름 길이는 범위 길이에 비례해야 함

 

 

N6: 인코딩을 피하라

- 이름에 유형 정보나 범위 정보를 넣으면 안됨

 

- 접두어❌

 

 

N7: 이름으로 부수 효과 설명

- 함수, 변수, 클래스가 하는 일을 모두 기술하는 이름으로 사용해야 함

 

 

 

테스트

T1: 불충분한 테스트

- 테스트 케이스는 잠재적으로 깨질 만한 부분을 모두 테스트 해야 함

 

 

T2: 테스트 커버리지 도구 사용

- 테스트가 빠뜨리지 공백을 알려줌

 

 

T3: 사소한 테스트를 건너뛰지 마라

 

 

T4: 무시한 테스트는 모호함을 뜻함

- 불분명한 요구사항은 테스트케이스를 주석으로 처리하거나 테스트 케이스에 @Ignore를 붙여 표현

 

 

T5: 경계 조건 테스트

 

 

T6: 버그 주변은 철저히 테스트

- 한 함수에서 버그를 발견했다면 근처에서 발견 할 가능성이 높음

 

 

T7: 실패 패턴 살피기

- 테스트 케이스가 실패하는 패턴으로 문제 진단

 

 

T8: 테스트 커버리지 패턴 살피기

- 통과하는 테스트가 실행하거나 실행하지 않는 코드를 살펴보면 실패하는 테스트케이스의 원인이 나타남

 

 

T9: 테스트는 빨라야 함