3. 코드 속의 나쁜 냄새

3.1 중복된 코드(Duplicated Code)

한 클래스의 서로 다른 메소드 안에 같은 코드가 있는 경우 Extract Method를 하고, 뽑아낸 메소드를 두 메소드안에서 호출

동일한 수퍼클래스를 갖는 두 서브클래스에서 같은 코드가 있는 경우, 양쪽 클래스에서 Extract Method를 하고, Pull Up Method를 사용. 만약 비슷하나 같지는 않으면 비슷한 부분과 다른 부분을 분리하기 위해 Extract Method를 사용한다음 FormTemplete Method를 사용할 수 있는지 검토. 그 메소드들이 같은 작업을 하나 다른 알고리즘을 사용한다면 두 알고리즘중 더 명확한 것을 선택한다음 Substitute Algorithm을 사용

서로 관계없는 두 클래스에서 중복된 코드가 있는경우 한쪽 클래스에서 Extract Class를 사용한 다음 양쪽에서 이 새로운 클래스를 사용.
메소드가 클래스 중 하나에 포함되어 있고 다른 클래스에서 호출되어야 하거나,세번째 클래스에 속하는 그 메소드가 원래 두 클래스에서 참조되어야 하는 경우, 메소드가 어디에 있는 것이 적당한지 결정하고, 적절한 곳에 위치하게 할 것

3.2 긴 메소드(Long Method)

메소드의 길이를 줄이기 위해, 짧은 메소드 단위로 분해하라.
메소드 호출이 원래 코드보다 더 길어지는 경우라도 메소드 이름이 코드의 목적을 잘 설명할 수 있으면 이 작업을 하라.

메소드 분해는 주석과 조건문, 루프를 기준단위로 고려해라.

3.3 거대한 클래스(Large Class)

하나의 클래스가 많은 일을 하는경우 많은 인스턴스 변수가 나타난다.
클래스 내에 서로에게 의미가 있는 변수를 골라서 묶는다.

코드가 많은 클래스는 Extract Class나 Extract Subclass를 한다.

3.4 긴 파라미터 리스트(Long Parameter List)

파라미터 리스트는 짧은 것이 좋으며, 객체를 사용하는 경우, 객체를 넘기는 방법으로 해결한다.

3.5 확산적 변경(Divergent Change)

여러 종류의 변경때문에 하나의 클래스가 시달리는 경우
특정 원인에 대해 변해야 하는 것을 모두 찾은 다음 Extract Class를 사용하여 하나로 묶음

3.6 산탄총 수술(Shotgun Surgery)

하나를 변경했을 때 많은 클래스를 고쳐야 할 경우, 하나의 클래스로 몰아넣기를 고려

3.7 기능에 대한 욕심(Feature Envy)

메소드가 자신이 속해있는 클래스보다 다른 클래스에 많은 관심을 가지고 있을때, 해당 메소드를 적절한 위치로 ?겨줄것.

3.8 데이터 덩어리(Data Clump)

함께 몰려다니는 데이터의 무리는 그들 자신의 객체로 만들어져야 함.

3.9 기본 타입에 대한 강박관념(Primitive Obsession)

3.10 Switch문(Switch Statements)

Switch문을 만나면 다형성을 생각해라.
Extract Method를 사용하여 switch문을 뽑아내고 Meve Method를 사용하여 다형성이 필요한 클래스로 옮김

3.11 평행 상속 구조(Parallel Inheritance Hierarchies)

한 클래스의 서브클래스를 만들면, 다른 곳에서도 모두 서브클래스를 만들어줘야함.
그러므로, 한쪽 상속구조와 인스턴스가 다른 구조의 인스턴스를 참조하도록 만든다.

3.12 게으른 클래스(Lazy Class)

클래스 생성시 유지에 대한 비용이 발생하므로, 비용대비 충분한 일을 하지 않는 클래스튼 삭제가 되어야함

3.13 추측성 일반화(Speculative Generality)

현재 필요하지도 않은 기능에 대하여, 추측적인 기능이 존재할 경우 제거한다.

3.14 임시 필드(Temporary Field)

객체 안의 인스턴스 변수가 특정상황에만 세팅되는 경우, 해당 변수들을 위한 Extract Class를 만들고 해당 변수를 사용하는 코드를 모두 새로운 Class에 넣는다.

3.15 메시지 체인(Message Chains)

어떤 객체를 얻기위해 메시지 체인이 생기는 경우 Hide Delegate를 사용하여 해결

3.16 미들 맨(Middle Man)

클래스의 인터페이스가 메소드의 대부분이 다른 클래스로 위임하고 있다면 Remove Middle Man을 사용하여 그 객체에 실제 머가 어떻되어가고 있는지를 알게 해준다.

3.17 부적절한 친밀(Inappropriate Intimacy)

지나치게 친밀한 클래스는 Move Method나 Move Field를 사용하여 친밀함을 줄림

3.18 다른 인터페이스르 가진 대체 클래스(Alternative Classes with Different Interface)

같은 작업을 하나 다른 Signature를 가지는 메소드는 Rename Method를 사용

3.19 불완전한 라이브러리 클래스(Incomplete Library Class)

라이브러리 클래스가 가지고 있었으면 하는 메소드가 몇개 있다면 Introduce Foreign Method를 사용하고 별도의 동작이 있다면 Introduce Local Exxtension이 필요

3.20 데이터 클래스(Data Class)

get/set 메소드만 가지고 있는 클래스는 Encapsulate Field를 적용한다.

3.21 거부된 유산(Refused Bequest)

서브클래스가 부모클래스로부터 상속 받은 것을 원치 않는다는 것은 클래스 상속구조가 잘못되었다는 것을 뜻하며, 새로운 클래스를 만들고 원치않는 메소드를 모두 형제 클래스로 옮긴다.

3.22 주석(Comments)

주석을 써야할 것 같으면, 먼저 코드를 리팩토링하여 주석이 불필요하도록 하라.

코드 블록이 무슨 작업을 하는지 설명하기 위해 주석이 필요하다면 Extract Method를 시도하고, 메소드가 이미 추출되었는데도 주석이 필요하다면 Rename Method를 사용, 시스템의 필요한 상태에 대한 어떠한 규칙을 설명할 필요가 있다면 Introduce Assertion을 사용할 것

주석은 무엇을 해야할 지 모를 때, 불확실한 것, 어떤 것을 왜 그렇게 했는지를 표시할 때 유용