2011년 5월 26일 목요일

코드 속의 나쁜 냄새

@ 중복된 코드(Duplicated Code)
- 한 클래스의 서로 다른 두 메소드 안에 같은 코드 : Extract Method(136)
- 동일한 수퍼클래스를 갖는 두 서브클래스에서 같은 코드 : Extract Method(136), Pull Up Method(370)
- 만약 코드가 비슷하기는 하지만 같지는 않다면, 비슷한 부분과 다른 부분을 분리한다. :
  Extract Method(136), Form Template Method(393)
- 메소드 들이 같은 작업을 하지만 다른 알고리즘을 사용한다면, 두 알고리즘 중 더 명확한 것을 선택 :
  Substitute Algorithm(167)
- 서로 관계없는 두 클래스에서 중복된 코드가 사용 : Extract Class(179)
@ 긴 메소드(Long Method)
- 메소드를 분해하는데 훨씬 더 공격적이어야 한다. 우리가 따르는 방법은, 어떤 것에 대한
 주석을 달아야 할 필요를 느낄 때마다 대신 메소드를 작성한다.
- 메소드의 길이를 줄이기 위해 : Extract Method(136)
- 메소드에 파라미터와 임시변수가 많다면 : Replace Temp with Query(147),
 Introduce Parameter Object(339), Preserve Whole Object(331)
- 노력했지만 여전히 임시변수와 파라미터가 많다면 : Replace Method with Method Object(163)
- 조건문과 루프 또한 메소드 추출이 필요하다는 신호를 준다 : Decompose Conditional(276)
@ 거대한 클래스(Large Class)
- 클래스가 지나치게 많은 인스턴스 변수를 갖는 경우 : Extract Class(179)
- 클래스 안에서 변수들의 어떤 부분집합에 대한 공통적인 접두사, 접미사가 있으면 클래스를 따로 뽑아낼수
 있다. 만약 새로 만들 클래스가 서브클래스로서 의미가 있으면 : Extract Subclass(378)
- 클래스가 모든 인스턴스 변수를 항상 다 사용하지 않는다면 : Extract Class(179), Extract Subclass(378)여러번 반복
- 코드가 많은 클래스에 대한 해결 : Extract Class(179), Extract Subclass(378)
- 클라이언트가 클래스를 어떻게 쓰게 할것인지를 결정하고 각각의 사용 방법에 대해 : Extract Interface(389)
@ 긴 파라미터 리스트(Long Parameter List)
- 대부분의 변경은 객체를 넘김으로써 없어진다.
- 이미 알고 있는 객체에 요청하여 파라미터의 데이터를 얻을 수있으면 : Replace Parameter with Method(335)
- 한 객체로부터 주워 모은 데이터 뭉치를 그 객체 자체로 바꾸기 위해 : Preserve Whole Object(331)
@ 확산형 변경(Divergent Change)
- 어떤 클래스를 보고는”새로운 데이터베이스를 추가할 때마다 항상 이 세 개의 메소드를 수정해야 하는군” 또는 “새로운 어음이 있을 때마다 항상 이 네개의 메소드를 변경해야 하는 군”하고 말한다면, 하나보다는 두개의 객체로 만드는 것이 더 좋은 상황에 있는 것이다.
- 특정 원인에 대해 변해야 하는 것을 모두 찾은 다음 : Extract Class(199)
@ 산탄총 수술(Shotgun Surgery)
- 변경을 할 때마다 많은 클래스를 조금씩 수정해야 한다면
- 이런 경우 Move Method(170)와 Move Field(175)를 사용하여 변경해야 할 부분을 모두 하나의 클래스로 몰아 넣는다.
- 만약 기존의 클래스 중에서 메소드나 필드가 옮겨갈 적절한 후보가 없다면 새로 만든다.
- 종종 Inline Class(184)를 사용하여 모든 동작을 하나로 모을 수도 있다.
@ 기능에 대한 욕심(Feature Envy)
- 메소드가 자신이 속한 클래스보다 다른 클래스에 관심을 가지고 있는 경우
- 어떤 값을 계산하기위해 다른 객체에 있는 여러 개의 get메소드를 호출하는 경우 등: Move Method(170)을 사용한다.
- 메소드의 특정 부분만 이런 욕심으로 고통 받는데 이럴 때는 욕심이 많은 부분에 대해서 Extract Method(136)를 사용한 다음 적절한 위치로 옮겨주기 위해 Move Method(170)를 사용한다.
- 종종 여러 개의 클래스의 기능을 사용하는 경우 데이터를 가장 많이 사용하는 클래스로 옮겨준다.
- 가장 기본적인 규칙은 같이 변하는 것을 모으는 것이다. 데이터와 그 데이터를 이용하는 동작은 보통 같이 변하지만, 예외도 있다. 이런 예외의 경우는 동작을 옮겨서 한 곳에서만 변하도록 한다.
@ 데이터 덩어리(Data Clump)
- 함께 몰려다니는 데이터의 무리는 그들 자신의 객체로 만들어져야 한다.
- 첫번째 필드로 나타나는 덩어리들이 있는 곳을 찾는 것이다. 이필드들에 대해 Extract Class(179)를 사용한다. 다음 관심을 메소드 시그너처로 돌려 Introduce Parameter Object(339), Preserve Whole Object(331)를 사용하여 파라미터 리스트를 단순하게 한다.
@ 기본타입에 대한 강박관렴(Primitive Obsession)
- 보통 수와 화폐단위를 묶는 Money클래스나, 상한과 하한을 가지는 Range클래스, 전화번호나 우편번호 같은 특정한 문자열을 위한 클래스와 같은 작은 작업을 위해 작은 객체를 사용하라
@ Switch 문(Switch Statements)
- 모든 switch 문을 찾아 바꿔 주어야 한다. 객체지향 개념 중 다형성이 이런 문제를 다루는 훌륭한 방법이다.
- Extract Method(136)를 사용하여 switch문을 뽑아내고, Move Method(170)를 사용하여 다형성이 필요한 클래스로 옮긴다.
- 만약 하나의 메소드에만 영향을 미치는 몇 개의 경우가 있다면, 굳이 바꿀 필요가 없다.
@ 평행 상속 구조(Parallel Inheritance Hierarchies)
- 산탄총 수술의 특별한 경우 이런 경우 한 클래스의 서브클래스를 만들면, 다른 곳에도 모두 서브 클래스를 만들어주어야 한다.
- 중복을 제거하는 일반적인 전력은 한쪽 상속 구조의 인스턴스가 다른 쪽 구조의 인스턴스를 참조하도록 만드는 것이다.
@ 게이른 클래스(Lazy Class)
- 만약 별로 하는 일이 없는 클래스의 서브클래스가 있다면 : Collapse Hierarchy(392)
- 거의 필요 없는 클래스에 대해서는 : Inline Class(184)
@ 추측성 일반화(Speculative Generality)
- 추측에 의한 일반적인 개발은 불필요한 부분을 생산 하는 경우가 많다.
- 만약 별로 하는 일이 없는 추상 클래스가 있다면 : Collapse Hierarchy(392)
- 불필요한 위임은 : Inline Class(184)
- 메소드에 사용되지 않는 파라미터가 있다면: Remove Parameter(318)
- 메소드 이름이 이상하고, 추상적일 때는 Rename Method(313)
@ 임시 필드(Temporary Field)
- 인스턴스 변수가 특정 상황에서만 세팅되는 경우
- 임시 필드는 복잡한 알고리즘이 여러 변수를 필요로 할 때 흔히 나타난다. 왜냐하면 아주 많은 값을 파라미터로 넘기는 것을 원치 않기 때문이다. 이런 경우 필요한 변수와 메소드를 묶어 Extract Class(179)를 사용할 수 있다.
@ 메시지 체인(Message Chains)
- 클라이언트가 어떤 객체를 얻기 위해 다른 객체에 물어보고, 다른 객체는 다시 또 다른 객체에 물어보고, 그 객체는 다시 다른 객체에 물어보고… 이런 경우 메시지 체인이라 한다.
- 이런 식으로 진행되는 것은 클라이언트가 클래스 구조와 결합되어 있다는 것을 뜻한다.
- Hide Delegate(187), Extract Method(136), Move Method(170)
@ 미들 맨(Middle Man)
- 클래스의 인터페이스를 보니 메소드의 태반이 다른 클래스로 위임을 하고 있다며Remove Middle Man(191)을 사용하여 그 객체에 실제로 뭐가 어떻게 되어가고 있는지를 알게 해준다.
- 만약 몇몇 메소드가 많은 일을 하지 않느다면 Inline Method(144)를 사용하여 호출하는 곳에 코드를 삽입 할 수 있다.
- 만약 추가 동작이 있다면 Replace Delegation with Inheritance(404)를 사용하여 미들맨을 실제 객체의 서브 클래스로 바꿀 수도 있다.
@ 부적절한 친밀(Inappropriate Intimacy)
- 지나치게 친밀한 클래스는 떼어 놓아야 한다.Move Method(170), Move Field(175)를 사용하여 조각으로 나누고, 친밀함을 줄여야 한다.
- Change Bidirectional Association to Unidirectional(236)이 적용 가능한지 보라.
- 이들 클래스에 공통 관심사가 있다면 Extract Class(179)를 사용하여 공통된 부분을 안전한 곳으로 빼내서 별도의 클래스를 만든다. 또는 Hide Delegate(487)를 사용하여 다른 클래스가 중개하도록 한다.
@ 다른 인터페이스를 가진 대체 클래스(Alternative Classes with Different Interface)
- 같은 작업을 하지만 다른 시그너처를 가지는 메소드에 대해서는 Rename Method(313)를 사용한다. 프로토콜이 같아질 때까지 Move Method(170)를 이용하여 동작을 이동시킨다.
- 너무 많은 코드를 옮겨야 할때에는 목적을 이루기 위해 Extract Superclass(384)를 사용할 수 있다.
@ 불완전한 라이브러리 클래스(Incomplete Library Class)
- 라이브러리 클래스가 가지고 있었으면 하는 메소드가 몇 개 있다면 Introduce Foreign Method(194)를 사용하라.
- 별도의 동작이 잔뜩 있다면 Introduce Local Extension(196)이 필요하다.
@ 데이터 클래스(Data Class)
- 필드와 각 필드에 대한 get/set메소드만 가지고, 다른것은 아무것도 없는 클래스도 있다. 이런 클래스는 멍청하게 데이터만 저장하고 거의 대부분 다른 클래스에 의해 조작된다. 이런 클래스는 public필드를 가질 것이다. Encapsulate Field(242)를 적용해야 한다.
- 만약 컬렉션(Collection)필드를 가지고 있다면 적절히 캡슐화 되어 있는지 확인하고, 적절히 캡슐화가 되어 있지 않으면 Encapsulate Collection(244)을 적용한다.
- 값이 변경되면 안되는 필드에 대해서는 Remove setting Method(344)를 사용한다.
- Get/set메소드가 다른 클래스에서 사용되는지를 찾아보고, 동작을 데이터 클래스로 옮기기 위해 Move Method(170)를 시도한다. 메소드 전체를 옮길 수 없을 때는 Extract Method(136)를 사용해서, 옮길 수 있는 메소드를 만들어라.
@ 거부된 유산(Refused Bequest)
- 전통적으로 “모든 수퍼 클래스는 추상 클래스여야 한다”
@ 주석(Comments)
- 주석을 써야 할 것 같은 생각이 들면, 먼저 코드를 리팩토링 하여 주석이 불필요하도록 한다.
- 주석을 사용하기 좋을 때는 무엇을 해야 할지를 모를 때
- 주석은 무엇이 진행되고 있는 지를 설명할 뿐이다.
- 어떤 것을 왜 이렇게 했는지를 표시하는데 주석을 써도 좋다.
- 특히 잊어버리기 쉬운 것을 표시할때는 좋다.

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...