코드의 구린내¶
목록¶
- 중복코드
- 장황한 메서드
- 방대한 클래스
- 과다한 매개변수
- 수정의 산발
- 기능의 산재
- 잘못된 소속
- 데이터 뭉치
- 강박적 기본 타입 사용
- switch 문
- 평행 상속 계층
- 직무유기 클래스
- 막연한 범용 코드
- 임시 필드
- 메시지 체인
- 과잉 중개 메서드
- 지나친 관여
- 인터페이스가 다른 대용 클래스
- 미흡한 라이브러리 클래스
- 데이터 클래스
- 방치된 상속물
- 불필요한 주석
중복코드¶
구린내의 제왕. 똑같은 코드 구조가 두 군데 이상 있을 때는 하나로 통일하면 프로그램이 개선된다.
예)
- 한 클래스의 두 메서드 안에 같은 코드가 들어 있는 경우.
==> [메서드 추출]기법 적용
- 한 클래스의 두 하위 클래스에 같은 코드가 들어 있는 경우.
==> [메서드 추출]기법 적용 후 [메서드 상향]기법 적용
- 코드가 똑같지 않고 비슷하다면 경우에 따라 [템플릿 메서드]기법 적용.
- 두 메서드가 알고리즘만 다르고 기능이 같다면 두 알고리즘 중 더 간단한 것을 택해서 [알고리즘 전환]기법을 적용.
- 중복 코드가 메서드 가운데에 있다면 [주변 메서드 추출]을 적용.
- 서로 상관없는 두 클래스 안에 중복 코드가 있을 때는 [클래스 추출]이나 [모듈 추출]을 적용.
제 삼의 클래스나 모듈로 떼어내거나 두 클래스 중 하나에 넣고 다른 클래스에서 호출하도록 한다.
장황한 메서드¶
최적의 상태로 장수하는 객체 프로그램을 보면 공통적으로 메서드 길이가 짧다. 현대의 객체지향 언어는 프로세스 내부 호출에 따른 오버헤드가 현저히 적다.
대신 하위 프로시저의 기능을 알려면 환경을 전환해야 하므로 코드를 보고 이해하려는 사람의 머릿속에 오버헤드가 생기게 됐다.
짧은 메서드를 이해하기 쉽게 하려면 메서드명을 잘 정해야 한다. 메서드의 기능을 한눈에 알 수 있는 메서드 명을 사용하면 그 메서드 안의 코드를 분석하지 않아도 된다.
이를 위해서는 메서드를 훨씬 과감하게 쪼개야 한다. 주석을 달아야할 것 같은 부분에 주석을 넣는 대신 메서드를 작성한다. 그 메서드 명은 기능 수행 방식이 아니라 목적, 기능 자체를 나타내는 이름으로 정한다. 이 방법은 코드가 한 줄짜리든 여러 줄짜리든 상관없이 적용할 수 있다. 원래 코드보다 길어지는 한이 있어도, 메서드명은 그 코드의 의도를 잘 반영하는 것으로 정해야 한다.
메서드를 줄이려면 십중팔구는 [메서드 추출]기법을 적용해야 한다. 하나로 묶으면 좋을 만한 부분들을 찾아내어 메서드로 만드는 것이다.
메서드에 매개변수나 임시변수가 많으면 [메서드 추출]을 실시하기가 까다롭다.
수많은 매개변수와 임시변수를 새로 만든 메서드의 매개변수로 넘기면 가독성에서 원래의 코드와 별 다를게 없어진다.
웬만한 경우에는 임시변수를 [메서드 호출로 전환]기법이나 [메서드 체인으로 전환]기법을 적용해 제거하자.
길게 열거된 매개변수는 [매개변수 세트를 객체로 전환]기법과 [객체를 통째로 전달]기법을 적용하면 간결해진다.
이런 리팩토링 기법을 적용했어도 여전히 임시변수와 매개 변수가 너무 많을 때는 [메서드를 메서드 객체로 전환]기법을 적용하면 된다.
조건문과 루프도 역시 메서드로 빼야 한다. 조건문을 추출하려면 [조건문 쪼개기]기법을 사용해야 한다.
[루프를 컬렉션 클로저 메서드로 전환]을 실시한 후, 그 클로저 메서드 호출과 클로저 자체에 [메서드 추출]을 실시하면 된다.
방대한 클래스¶
기능이 지나치게 많은 클래스에는 보통 엄청난 수의 인스턴스 변수가 들어 있다. 클래스에 인스턴스 변수가 너무 많으면 중복 코드가 반드시 존재하게 마련이다.
[클래스 추출]을 실시하면 수많은 인스턴스 변수를 하나로 묶을 수 있다.
서로 연관된 변수를 골라서 클래스로 빼내면 된다.
하위 클래스로 추출하는 것이 적합할 것 같으면 [하위클래스 추출]을 실시하는 것이 더 간단하다.
만약 추출할 클래스가 대리자로 부적절할 것 같으면 [모듈 추출]을 실시하면 된다.
코드 분량이 너무 방대한 클래스에 대해서 위의 방법 외에
클라이언트가 그 클래스를 어떻게 사용할지 결정하게 하고, 사용 방법마다 [인터페이스 추출]을 실시하는 방법도 있다.
방대한 클래스가 GUI 클래스라면 데이터와 기능을 서로 다른 도메인 객체로 옮겨야 할 수도 있다.
이를 위해 일부 중복 데이터는 놔두고 그 데이터와 싱크를 유지해야 할 수도 있다. 이것은 [관측 데이터 복제]기법을 실시하면 된다.
과다한 매개변수¶
매개변수 세트가 간결하다는 것은 장점이다. 매개변수 세트가 길면 서로 일관성이 없어지거나 사용이 불편해지고, 더 많은 데이터가 필요할 때마다 계속 수정해야 하기 때문에 그 매개변수들을 이해하기가 힘들다.
이미 알고 있는 객체에 요청하여 데이터를 가져올 수 있을 때는 [매개변수 세트를 메서드로 전환]을 적용하면 된다.
[객체를 통째로 전달], [매개변수 세트를 객체로 전환]등의 방법도 있다.
호출되는 객체가 호출 객체에 의존하면 안 될 때는 예외다.
이럴 때는 데이터를 개별적으로 빼서 매개변수로 전달하는 것이 바람직하지만, 어려움이 따른다.
나열된 매개변수 세트가 너무 길거나 자주 바뀐다면 불가피하게 종속 구조를 유지하는 것도 생각해봐야 한다.
수정의 산발¶
수정의 산발은 한 클래스가 다양한 원인 때문에 다양한 방식으로 자주 수정될 때 일어난다. 각 객체는 한 종류의 수정에 의해서만 변경되는 것이 좋다.
수정의 산발이 발생하는 경우(금융 상품을 추가할 때마다 4개의 메서드를 수정해야 하는 등),
특정 원인으로 변하는 모든 부분을 찾은 후 [클래스 추출]을 적용해서 그 부분들을 합쳐 한 클래스로 빼내야 한다.
기능의 산재¶
기능의 산재는 수정의 산발과 비슷하지만 정 반대다. 수정할 때마다 여러 클래스에서 수많은 자잘한 부분을 고쳐야 한다면 이 문제를 의심할 수 있다. 수정할 부분이 여기저기에 있다면 찾기도 힘들 뿐더러 꼭 수정해야 하는 부분을 놓치기 쉽다.
이럴 때는 [메서드 이동]과 [필드 이동]을 적용해 수정할 부분들을 전부 하나의 클래스 안에 넣어야 한다.
기존의 클래스 중 어느 것에 넣기도 부적절해 보일 때는 새 클래스를 만들어야 한다.
대개는 [클래스 내용 직접 삽입]을 적용해서 별도 클래스에 분산되어 있던 모든 기능을 한 곳으로 가져와도 된다.
<수정의 산발> 문제가 조금 생기지만, 간단히 처리할 수 있다.
<수정의 산발>은 한 클래스에 여러 수정이 발생하는 문제이고, <기능의 산재>는 하나의 수정으로 여러 클래스가 바뀌게 되는 문제다.
둘 중 어느 것이든 수정과 클래스가 일대일 대응되게 깔끔히 정리해야 한다.
잘못된 소속¶
객체의 핵심은 데이터와 그 데이터에 사용되는 프로세스를 한 데 묶는 기술이라는 점이다.
전통적으로 어떤 메서드가 자신이 속하지 않은 클래스에 더 많이 접근한다면 <잘못된 소속>의 구린내가 풍길 것이다.
잘못 소속된 메서드가 흔히 접근하는 대상은 데이터다.
소속이 잘못된 메서드는 더 많이 접근하는 클래스에 들어가는 것이 마땅하니,
[메서드 이동]기법을 실시해 더 자주 접근하는 클래스로 옮겨야 한다.
메서드의 일부만이 소속이 잘못된 경우, [메서드 추출]을 적용 후 [메서드 이동]을 적용해서 적절한 클래스로 옮기면 된다.
한 메서드가 여러 클래스에 들어 있는 기능을 이용할 때도 많은데,
이때는 문제의 메서드가 접근하는 데이터가 어느 클래스에 제일 많이 들어 있는지 파악해서 그 클래스로 옮긴다.
그러기 전에 [메서드 추출]을 실시해 그 메서드를 다른 클래스에 들어갈 여러 부분으로 쪼개면 작업이 더 쉬워진다.
이 규칙을 따르지 않는 복잡한 패턴도 있다. GOF의 디자인 패턴 중 [전략 패턴]과 [방문자 패턴], 켄트 백의 저서에 수록된 [자가 위임 패턴]이 그렇다.
데이터 뭉치¶
데이터 항목은 거리의 꼬마들처럼 몰려다니는 습성이 있다. 몰려 있는 데이터 뭉치는 객체로 만들어야 한다.
데이터 뭉치가 필드처럼 보이는 부분을 찾아야 한다.
뭉치를 객체로 전환하려면 그 필드들을 대상으로 [클래스 추출]기법을 적용해야 한다.
그리고 나서 메서드 시그니처를 대상으로 [매개변수 세트를 객체로 전환]기법과 [객체를 통째로 전달]기법을 적용하여 간결하게 만들어야 한다.
이렇게 하면 매개변수가 적어져서 부수적으로 메서드 호출 코드가 간결해지는 효과도 누릴 수 있다.
인스턴스 변수 세트와 매개변수 세트를 줄이면 분명히 의심되는 문제점도 없어지지만,
일단 객체로 전환하고 나면 전체적 성능이 개선될 여지도 있다.
이렇게 하고 나면 <잘못된 소속>의 구린내가 풍기는 부분들을 찾을 수 있는데,
이 구린 부분의 기능은 새 클래스로 빼내야 한다.
이렇게 새로 생긴 클래스로 인해 코드의 효율성은 높아진다.
강박적 기본 타입 사용¶
대개의 프로그래밍 환경을 구성하는 데이터는 두 종류다. 하나는 레코드 타입인데, 이를 사용해서 데이터를 의미 있는 그룹들로 묶어 구조화할 수 있다. 다른 하나는 기본 타입이다. 레코드에는 항상 일정 양의 오버헤드가 따른다. 객체의 주요 장점 중 하나가 바로 기본 타입 클래스와 응용 클래스 간의 경계를 허문다는 점이다. 언어에 내장된 기본 타입과 구별하기 힘든 작은 클래스를 손쉽게 작성할 수 있다. (다른 언어에선 기본 타입으로 존재하는 문자열과 날짜가 자바에선 클래스로 존재한다.)
객체를 처음 접하는 사람은 보통 숫자와 통화를 연동하는 돈 관련 클래스나 전화번호 유편번호 같은 특수 문자열 클래스 등의 사소한 작업에 작은 객체를 잘 사용하지 않으려는 경향이 있다.
이러한 우물 안 개구리를 벗어나려면 [데이터 값을 객체로 전환]을 실시하면 된다.
데이터 값이 분류 부호일 땐 그 값이 기능에 영향을 주지 않는다면 [분류 부호를 클래스로 전환] 기법을 적용하자.
뭉쳐 다녀야 할 여러 개의 필드가 있다면 [클래스 추출]기법을 적용해야 한다.
기본 타입이 매개변수 세트에 들어 있다면 [매개변수 세트를 객체로 전환]기법을 적용하면 된다.
배열 때문에 불편하다면 [배열을 객체로 전환]기법을 적용하면 된다.
switch 문¶
객체지향 코드의 확연한 특징 중 하나는 switch-case 문이 비교적 적게 사용된다는 점이다. switch문의 단점은 반드시 중복이 생긴다는 점이다. 같은 switch 문이 프로그램 곳곳에 있을 때가 많다. switch 문에 새 코드 행을 추가하려면 그렇게 여기저기에 존재하는 switch 문을 전부 찾아서 수정해야 한다. 이 문제점을 해결할 수 있는 최상의 방법은 객체지향 개념 중 하나인 다형성, 즉 재정의를 이용하는 것이다.
대부분의 switch 문은 고민할 필요 없이 재정의로 바꿔야 한다.
문제는 재정의를 넣을 위치다.
switch 문에는 분류 부호가 흔히 사용되는데, 그럴 땐 분류 부호 값이 들어 있는 메서드나 클래스가 있어야 한다.
이럴 때는 [메서드 추출]을 실시해서 switch 문을 메서드로 빼낸 후,
[메서드 이동]을 실시해서 그 메서드를 재정의해야할 클래스에 옮겨 넣으면 된다.
그와 동시에 [분류 부호를 하위클래스로 전환]기법과 [분류 부호를 상태/전략 패턴으로 전환]기법 중 어느 것을 적용할지 판단해야 한다.
상속 구조를 만들었다면 [조건문을 재정의로 전환]기법을 적용하면 된다.
하나의 메서드에 영향을 미치는 case문이 2~3개밖에 없고 나중에 그 모든 case문을 수정할 일이 없을 것 같으면,
재정의로 전환하는 것은 과하다.
그럴 때는 [매개변수를 메서드로 전환]을 적용하는 편이 낫다.
조건문이 들어 있는 여러 case 문 중 하나가 null일 때는 [null검사를 널 객체에 위임]을 실시하면 된다.
평행 상속 계층¶
평생 상속 계층은 사실 <기능의 산재>의 특수한 상황이다. 이 문제점이 있으면 한 클래스의 하위클래스를 만들 때마다 매번 다른 클래스의 하위클래스도 만들어야 한다. 서로 다른 두 상속 계층의 클래스명 접두어가 같으면 이 문제를 의심할 수 있다.
중복 코드 부분을 제거하려면
보통은 한 상속 계층의 인스턴스가 다른 상속 계층의 인스턴스를 참조하게 만들면 된다.
[메서드 이동]과 [필드 이동]을 실시하면
참조하는 클래스에 있는 계층이 제거된다.
직무유기 클래스¶
하나의 클래스를 작성할 때마자 유지관리와 이해를 위한 비용이 추가된다. 따라서 비용만큼의 기능을 수행하지 못하는 비효율적인 클래스는 없애야 한다. 기본에는 비용 대비 효율성이 좋았으나 리팩토링 실시로 인해 기능이 축소된 클래스, 또는 수정할 계획으로 작성했으나 수정을 실시하지 않아 쓸모없어진 클래스가 바로 이런 직무유기 클래스에 해당된다.
비용 대비 효율이 떨어지는 하위클래스나 모듈이 있을 때는 [계층 병합]을 실시하면 된다.
거의 쓸모없는 구성 요소에는 [클래스 내용 직접 삽입]이나 [모듈 내용 직접 삽입]기법을 적용해야 한다.
막연한 범용 코드¶
막연한 범용코드는 대체로 코드를 알아보고 유지보수하기가 더 어렵게 한다. 모든 부품(온갖 호출과 case문)이 전부 활용된다면야 문제가 없지만, 그렇지 않다면 장애물에 불과하니 제거해야 한다.
별다른 기능이 없는 클래스나 모듈이 있다면 [계층 병합]을 실시해야 하고,
불필요한 위임을 제거하려면 [클래스 내용 직접 삽입]을 실시해야 한다.
메서드에 사용되지 않는 매개변수가 있으면 [매개변수 제거]를 실시해야 하며,
메서드명이 이상하다면 [메서드명 변경]을 실시해야 한다.
메서드나 클래스가 오직 테스트 케이스에만 사용된다면 구린내를 풍기는 유력한 용의자로 막연한 범용 코드를 지목할 수 있다. 그런 메서드나 클래스를 발견하면 그것과 그것을 실행하는 테스트 케이스를 모두 삭제하자. 단, 적절한 기능을 실행하는 테스트 케이스용 헬퍼 메서드나 클래스는 당연히 삭제하면 안된다.
임시 필드¶
어떤 객체 안에 인스턴스 변수가 특정 상황에서만 할당되는 경우가 간혹 있다.
개발자는 객체가 그 안에 들어 있는 모든 변수를 이용하리라 생각하기 마련이므로 이런 코드는 파악하기 힘들다. 사용되지 않을 것 같은 변수가 어째서 거기 있는지 이해하려다 보면 스트레스를 받을 수 밖에 없다.
이런 가엾은 떠돌이 변수들이 서식할 집을 마련해 주려면 [클래스 추출]을 실시해야 한다.
그렇게 작성한 클래스에 그 변수들과 관련된 코드를 전부 넣어야 한다.
[null 검사를 널 객체에 위임]을 실시해서,
그 변수들의 값이 올바르지 않을 경우를 대비한 대체 컴포넌트를 작성하면
경우에 따라 조건문 코드를 없앨 수 있다.
임시 필드의 구린내는 복잡한 알고리즘에 여러 변수를 사용해야 할 때 풍긴다.
개발자는 수많은 매개변수를 전달하는 것을 꺼린 나머지,
매개변수를 필드에 대입한다.
그런데 인스턴스 변수는 해당 알고리즘이 실행되는 동안에만 효력이 있고
다른 때는 코드를 복잡하게 만들 뿐이다.
이럴 때는 인스턴스 변수와 그 변수를 사용하는 메서드 전부에 대해 [클래스 추출]을 적용하면 된다.
그러면 '메서드 객체'가 새로 생성된다.
메시지 체인¶
메시지 체인은 클라이언트가 한 객체에 제 2의 객체를 요청하면, 제2의 객체가 제 3의 객체를 요청하는 식으로 연쇄적 요청이 발생하는 문제점을 뜻한다. 이러한 메시지 체인은 수많은 코드 행이 든 get메서드나 임시변수 세트라고 봐도 된다. 이런 요청의 왕래로 인해 클라이언트는 그 왕래 자체에 구속된다. 그 사이의 관계들에 수정이 발생할 때마다 클라이언트도 수정해야 한다.
이럴 때는 [대리 객체 은폐]를 실시해야 한다. 이 기법은 원칙적으로 체인을 구성하는 모든 객체에 적용할 수 있지만,
그렇데 하면 모든 중간 객체가 중개 메서드로 변해서 <과잉 중개 메서드>의 구린내를 풍기는 문제가 흔히 발생한다.
그래서 차라리 결과 객체가 어느 대상에 사용되는지를 알아내는 방법이 더 낫다.
그렇게 알아낸 객체가 사용되는 코드 부분을 [메서드 추출]을 통해 별도의 메서드로 빼낸 후
[메서드 이동]을 실시해서 체인 아래로 밀어낼 수 있는지 여부를 검사해야 한다.
만약 체인에 속한 객체 중 한 객체의 여러 클라이언트가 나머지 객체들에 왕래한다면 그 기능을 수행하는 메서드를 추가하면 된다.
과잉 중개 메서드¶
객체의 주요 특징 한가지는 바로 캡슐화다. 캡슐화란 내부의 세부적인 처리를 외부에서 볼 수 없게 은폐하는 작업을 뜻한다. 캡슐화할 때는 대개 위임이 수반된다. 그러나 이것도 지나치면 문제가 된다.
어떤 클래스의 인터페이스를 보니까 그 안의 절반도 넘는 메서드가
기능을 다른 클래스에 위임하고 있다면,
조만간 [과앵 중개 메서드 제거]를 실시해서 원리가 구현된 객체에 직접 접근하자.
일부 메서드에 별 기능이 없다면, [메서드 내용 직접 삽입]을 실시해서 그 메서드들의 내용을 호출 객체에 직접 삽입하면 된다.
부수적인 기능이 있다면 [위임을 상속으로 전환] 기법을 실시해서 중개 메서드를 실제 객체의 하위 클래스로 전환하면 된다.
이렇게 하면 모든 위임을 추적하지 않고 기능을 확장할 수 있다.
지나친 관여¶
간혹 클래스끼리 관계가 지나치게 밀접한 나머지 서로의 은밀한 부분(private)을 알아내느라 과도한 시간을 낭비하게 될 때가 있다.
서로 지나치게 관여하는 클래스는 갈라놔야 한다.
[메서드 이동]과 [필드 이동]을 실시해서 각 클래스를 분리해서 지나친 관여를 줄여야 한다.
[클래스의 양방향 연결을 단방향으로 전환]기법을 적용할 수 있는지 판단해서
만약 해당 클래스들이 공통으로 필요로 하는 부분이 있다면,
[클래스 추출]을 실시해서 공통 필요 부분을 별도의 안전한 클래스로 빼내면 된다.
아니면 [대리 객체 은폐]를 실시하여 다른 클래스가 중개 메서드 역학을 하게 만들어도 된다.
상속으로 인해 지나친 관여가 발생하는 경우가 많다.
하위클래스는 항상 상위클래스가 공개하는 것보다 많은 데이터를 필요로 한다.
상위클래스에서 하위클래스를 빼내야할 경우에는 [상속을 위임으로 전환]기법을 적용해야 한다.
인터페이스가 다른 대용 클래스¶
기능은 같은데 시그니처가 다른 메서드에는 [메서드명 변경]을 실시해야 한다.
클래스에 여전히 충분한 기능이 구현되어 있지 않기 때문에 대체로 이 기법만 적용해선 충분하지 않다.
프로토콜이 같아질 때까지 [메서드 이동]을 실시해서 기능을 해당 클래스로 옮겨야 한다.
단, 코드를 너무 여러 번 옮겨야 한다면 [상위 클래스 추출]을 실시하면 된다.
미흡한 라이브러리 클래스¶
라이브러리 클래스 제작자라 해도 모든 걸 알 수는 없다.
라이브러리 클래스를 원하는 기능을 수행하게 수정하는 것이 보통은 불가능하다.
이 문제를 해결하기 위한 특수 목적의 기법이 두개 있다.
라이브러리 클래스에 넣어야 할 메서드가 두 개뿐이라면 [외래 클래스에 메서드 추가]기법을 실시하고,
부가 기능이 많을 때는 [국소적 상속확장 클래스 사용]기법을 실시하자.
데이터 클래스¶
데이터 클래스는 필드와 필드 읽기/쓰기 메서드만 들어 있는 클래스다.
그런 클래스는 오로지 데이터 보관만 담당하며, 거의 대부분의 구체적 데이터 조작은 다른 클래스가 수행한다.
필드가 public이라면 [필드 캡슐화]기법을 실시해야 한다.
컬렉션 필드가 있으면 그 필드가 적절히 캡슐화되어 있는지 확인하고, 그렇지 않다면 [컬렉션 캡슐화]기법을 적용하자.
변경되지 않아야 하는 필드에는 [쓰기 메서드 제거]를 적용하자.
이런 읽기/쓰기 메서드가 다른 클래스에 의해 사용되는 부분을 찾아서, [메서드 이동]을 실시해 기능을 그 데이터 클래스로 옮겨야 한다.
만약 메서드 전체를 옮길 수 없다면 [메서드 추출]을 실시해 옮길 수 있는 메서드를 작성하면 된다.
그러고 나서 읽기/쓰기 메서드에 [메서드 은폐]를 적용하면 된다.
방치된 상속물¶
하위 클래스는 부모 클래스의 메서드와 데이터를 상속받는다.
상속받은 메서드나 데이터가 하위 클래스에서 더 이상 쓰이지 않거나 필요 없을 땐 어떻게 될까?
기존에는 이 문제의 원인이 잘못된 계층 구조 때문이라고 설명했다.
이 경우, 새 대등 클래스를 작성하고 [메서드 하향], [필드 하향]을 실시해서 사용되지 않는 모든 메서드를
그 형제 클래스에 몰아넣어야 한다.
하지만 일부 기능을 언제든 재사용하고자 하위클래스로 몰아넣은 작업은 효과적일 때가 있다.
따라서 방치된 상속물로 인해 코드가 복잡해지거나 문제가 생길 때는 위에 설명한 기존 방법을 따르길 권한다.
이 문제는 심각하지 않은 경우가 대부분이기 때문에 리팩토링이 별로 필요하지 않다.
방치된 상속물의 구린내는 하위 클래스가 기능은 재사용하지만 상위클래스의 인터페이스를 지원하지 않을 때 훨씬 심하다.
상속 구현을 거부하는 것은 상관없지만, 인터페이스를 거부하는 것은 심각한 문제다.
그렇다고 계층 구조를 건드려서는 안 되고, [상속을 위임으로 전환] 기법을 적용해서 계층 구조를 없애야 한다.
불필요한 주석¶
주석이 다 필요 없다거나 작성하지 말자는 얘긴 아니다.
이 절에서 주석을 거론하는 이유는 주석이 구린내를 감춰주는 탈취제 용도로 쓰일 때가 많기 때문이다.
대체로 리팩토링을 실시하고 나면 주석들이 불필요한 것이었다는 사실을 알게된다.
어떤 코드 구간의 기능을 설명할 주석이 필요할 때는 [메서드 추출]을 실시해야 한다.
메서드가 이미 추출된 상태임에도 기능을 설명할 주석이 여전히 필요하다면, [메서드명 변경]을 실시해야 한다.
시스템의 필수적인 상태에 관해 약간의 규칙을 설명해야 할 때는 [어설션 넣기]를 실시하면 된다.
주석은 무슨 작업을 해야 좋을지 모를 때만 넣는 것이 좋다.
확실하지 않은 부분을 표시하거나, 어떤 코드를 넣은 이유를 메모해 놓을 때도 적절하다.
또 잊기 쉬운 사항을 주석으로 작성해 놓으면 나중에 수정하게 될 사람이 보고 쉽게 이해할 수 있다.