이번 장에서는 지금까지 배운 지저분한 코드를 정리한다.
나쁜 냄새 목록이니 가능한 한 기억하고 있다가 고치는 것이 좋다.
일반
한 소스 파일에 여러 언어를 사용한다
- HTML, 자바, 태그 라이브러리 구문, 영어 주석, Javadoc 등을 포함한 JSP 파일은 혼란스럽고 조잡하다.
- 이상적으로 소스 파일 하나에 언어 하나만 사용하는 방식이 가장 좋다.
당연한 동작을 구현하지 않는다
- 최소 놀람의 원칙에 의거해 함수나 클래스는 프로그래머가 당연하게 여길 만한 동작과 기능을 제공해야 한다.
경계를 올바르게 처리하지 않는다
- 직관에 의존하지 말고 모든 경계와 구석진 곳에서 코드를 증명해야 한다.
- 모든 경계 조건을 찾아내고, 모든 경계 조건을 테스트하는 테스트 케이스를 작성한다.
안전 절차 무시
- 컴파일러 경고 일부나 전체를 꺼버리면 빌드가 쉬워질지 모르지만, 자칫하면 끝없는 디버깅에 시달린다.
- 안전 절차를 무시하면 위험하다.
중복
- 코드에서 중복을 발견할 때마다 추상화할 기회로 간주한다.
- 중복된 코드를 하위 루틴이나 다른 클래스로 분리한다.
- 똑같은 코드가 여러 차례 나오는 것은 문제가 있는 것이다.
추상화 수준이 올바르지 못하다
- 모든 저차원 개념은 파생 클래스에 넣고, 모든 고차원 개념은 기초 클래스에 넣는다.
- 고차원 개념과 저차원 개념이 섞여서는 안 된다.
기초 클래스가 파생 클래스에 의존한다
- 기초 클래스가 파생 클래스를 사용한다면 뭔가 문제가 있는 것이다.
- 일반적으로 기초 클래슨느 파생 클래스를 아예 몰라야 한다.
과도한 정보
- 잘 정의된 모듈은 인터페이스가 아주 작다.
- 부실하게 정의된 모듈은 인터페이스가 구질구질하다.
- 잘 정의된 인터페이스는 많은 함수를 제공하지 않고, 그래서 결함도도 낮다.
- 부실하게 정의된 인터페이스는 반드시 호출해야 하는 온갖 함수를 제공한다. 그래서 결함도가 높다.
- 인터페이스를 매우 작게, 그리고 매우 깐깐하게 만들어야 한다. 그래야 정보가 제한되어 결합도가 낮아진다.
죽은 코드
- 죽은 코드는 시간이 지날수록 강한 악취를 풍긴다.
- 죽은 코드를 발견하면 장례식을 치러줘야 한다. 시스템에서 제거한다.
수직 분리
- 변수와 함수는 사용되는 위치에 가깝게 정의한다.
- 비공개 함수는 처음으로 호출한 직후에 정의한다.
일관성 부족
- 어떤 개념을 특정 방식으로 구현했다면 유사한 개념도 같은 방식으로 구현한다.
- 간단한 일관성만으로도 코드를 읽고 수정하기 쉬워진다.
모호한 의도
- 코드를 짤 때는 의도를 최대한 분명히 밝힌다.
- 행을 바꾸지 않고 표현한 수식, 헝가리식 표기법, 매직 번호 등은 모두 저자의 의도를 흐린다.
- 독자에게 의도를 분명히 표현하도록 시간을 투자할 가치가 있다.
부적절한 static 함수
- 특정 인스턴스와 관련되지 않을 때 사용하는 것이 좋다.
- 반드시 static 함수로 정의해야겠다면 재정의할 가능성은 없는지 꼼꼼히 따져본다.
서술적 변수
- 프로그램 가독성을 높이는 가장 효과적인 방법 중 하나가 서술적인 변수 이름을 사용하는 것이다.
- 좋은 변수 이름만 붙여도 해독하기 어렵던 모듈이 순식간에 읽기 쉬운 모듈로 바뀐다.
이름과 기능이 일치하는 함수
- 이름만으로 분명하지 않기에 구현을 살피거나 문서를 뒤적여야 한다면 좋지 못한 이름이다.
- 더 좋은 이름으로 바꾸거나 아니면 더 좋은 이름을 붙이기 쉽도록 기능을 정리해야 한다.
If, Switch문보다 다형성 사용
- 선택 유형 하나에는 switch 문을 한 번만 사용한다.
- 같은 선택을 수행하는 다른 코드에서는 다형성 객체를 생성하여 switch문을 대신한다.
매직 숫자는 명명된 상수로 교체
- 일반적으로 코드에서 숫자를 사용하지 말아야 하는 것이 규칙이다.
- 숫자는 명명된 상수 뒤로 숨기는 것이 좋다.
조건 캡슐화
- 부울 논리는 이해하기 어렵다. 조건의 의도를 분명히 밝히는 함수로 표현한다.
// 기존 코드
if (shouldBeDeleted(timer)
// 개선된 코드
if (timer.hasExpired() && !timer.isRecurrent())
부정 조건은 피한다
- 부정 조건은 긍정 조건보다 이해하기 어렵다 가능한 한 긍정 조건으로 표현한다.
// 기존 코드
if (!buffer.shouldNotCompact())
// 개선된 코드
if(buffer.shouldCompact())
함수는 한 가지만 해야 한다
- 한 가지만 수행하는 좀 더 작은 함수 여럿으로 나누어야 마땅하다.
- SOLID 원칙 중 하나인 SRP를 고려해야 한다.
숨겨진 시간적인 결합
- 함수를 짤 때는 함수 인수를 적절히 배치해 함수가 호출되는 순서를 명백히 드러낸다.
- 메서드가 제자리를 찾으면 변수들이 시간적인 결합을 좀 더 명백히 드러낼 것이다.
함수는 추상화 수준을 한 단계만 내려가야 한다
- 추상화 수준은 함수 이름이 의미하는 작업보다 한 단계만 낮아야 한다.
설정 정보는 최상위 단계에 두어야 한다
- 추상화 최상위 단계에 둬야 할 기본값 상수나설정 관련 상수를 저차원 함수에 숨겨서는 아 ㄴ된다.
- 대신 고차원 함수에서 저차원 함수를 호출할 때 인수로 넘긴다.
'Book > 클린코드' 카테고리의 다른 글
[클린코드] 17장 냄새와 휴리스틱 (주석, 환경, 함수, 자바, 이름, 테스트) (0) | 2023.09.21 |
---|---|
[클린코드] 16장 SerialDate 리팩토링 (0) | 2023.09.21 |
[클린코드] 15장 JUnit 들여다보기 (0) | 2023.09.21 |
[클린코드] 14장 점진적인 개선 (0) | 2023.09.21 |
[클린코드] 13장 동시성 (0) | 2023.09.17 |