자주 리펙토링을 하라.(3)

|



리펙토링을 실제로 어떻게 수행하는지.. 마틴 파울러(Martin Fowler)의 리펙토링 책에 나온 내용을 요약합니다.

여기에 정리한 내용은 인덱스 정도로 활용하시고.. 실제 리펙토링을 위한 예제나 자세한 설명은 책을 참고하시기 바랍니다.

1. 메소드 정리 (Composing Methods)

Extract Method (136)
그룹으로 함께 묶을 수 있는 코드 조각이 있으면, 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 뽑아낸다.

Inline Method (144)
메소드 몸체가 메소드의 이름 만큼이나 명확할 때는, 호출하는 곳에 메소드의 몸체를 넣고 메소드를 삭제하라

Inline Temp (146)
간단한 수식의 결과값을 가지는 임시변수가 있고, 그 임시변수가 다른 리펙토링을 하는데 방해가 된다면, 이 임시변수를 참조하는 부분을 모두 원래의 수식으로 바꾸라

Replace Temp with Query (147)
어떤 수식의 결과값을 저장하기 위해서 임시변수를 사용하고 있다면, 수식을 뽑아내서 메소드로 만들고 임시변수를 참조하는 곳을 찾아 모두 메소드 호출로 바꾼다. 새로 만든 메소드는 다른 메소드에서도 사용될 수 있다.

Introduce Explaining Variable (151)
복잡한 수식이 있는 경우에는, 수식의 결과나 또는 수식의 일부에 자신의 목적을 잘 설명하는 이름으로 된 임시변수를 사용하라.

Split Temporary Variable (155)
루프 안에 있는 변수나 collecting temporary variable도 아닌 임시변수에 값을 여러 번 대입하는 경우에는, 각각의 대입에 대해서 따로따로 임시변수를 만들어라.

Remove Assignments to Parameters (159)
파라미터에 값을 대입하는 코드가 있으면, 대신 임시변수를 사용하도록 하라.

Replace Method with Method Object (163)
긴 메소드가 있는데 지역변수 때문에 Extract Method를 적용할 수 없는 경우에는, 메소드를 그 자신을 위한 객체로 바꿔서 모든 지역변수가 그 객체의 필드가 되도록 한다. 이렇게 하면 메소드를 같은 객체 안의 여러 메소드로 분해할 수 있다.

Substitute Algorithm (167)
알고리즘을 보다 명확한 것으로 바꾸고 싶을 때는, 메소드의 몸체를 새로운 알고리즘으로 바꾼다.

2. 객체간의 기능 이동

Move Method (170)
메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용하고 있다면, 이 메소드를 가장 많이 사용하고 있는 클래스에 비슷한 몸체를 가진 새로운 메소드를 만들어라. 그리고 이전 메소드는 간단한 위임으로 바꾸거나 완전히 제거하라.

Move Field (175)
필드가 자신이 정의된 클래스보다 다른 클래스에 의해서 더 많이 사용되고 있다면, 타켓 클래스에 새로운 필드를 만들고 기존 필드를 사용하고 있는 모든 부분을 변경하라.

Extract Class (179)
두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우, 새로운 클래스를 만들어서 관련 있는 필드와 메소드를 예전 클래스에서 새로운 클래스로 옮겨라.

Inline Class (184)
클래스가 하는 일이 많지 않은 경우에는, 그 클래스에 있는 모든 변수와 메소드를 다른 클래스로 옮기고 그 클래스를 제거하라.

Hide Delegate (187)
클래스가 객체의 위임 클래스를 직접 호출하고 있는 경우, 서버에 메소드를 만들어서 대리객체를 숨겨라.

Remove Middle Man (191)
클래스가 간단한 위임을 너무 많이 하고 있는 경우에는, 클라이언트가 대리객체를 직접 호출하도록 하라.

Introduce Foreign Method (194)
사용하고 있는 서버 클래스에 부가적인 메소드가 필요하지만 클래스를 수정할 수 없는 경우에는, 첫 번째 인자로 서버 클래스의 인스턴스를 받는 메소드를 클라이언트에 만들어라.

Introduce Local Extension (196)
사용하고 있는 서버 클래스에 여러 개의 메소드를 추가할 필요가 있지만 서버 클래스를 수정할 수 없는 경우, 필요한 추가 메소드를 포함하는 새로운 클래스를 만들어라. 이 확장 클래스를 원래 클래스의 서브클래스 또는 래퍼 클래스로 만들어라.

3. 데이터 구성 (Organizing Data)

Self Encapsulate Field (205)
필드에 직접 접근하고 있는 필드에 대한 결합이 이상해지면, 그 필드에 대한 get/set 메소드를 만들고 항상 이 메소드를 사용하여 필드에 접근하라.

Replace Data Value with Object (209)
추가적인 데이터나 동작을 필요로 하는 데이터 아이템이 있을 때는, 데이터 아이템을 객체로 바꾸어라.

Change Value to Reference (213)
동일한 인스턴스를 여러 개 가지고 있는 클래스가 있고 여러 개의 동일한 인스턴스를 하나의 객체로 바꾸고 싶으면, 그 객체를 참조 객체로 바꾸어라.

Change Reference to Value (217)
직고, 불변성(immutable)이고 관리하기 어려운 참조 객체가 있는 경우, 그것을 값 객체로 바꾸어라.

Replace Array with Object (220)
배열의 특정 요소가 다른 뜻을 가지고 있다면, 배열을 각각의 요소에 대한 필드를 가지는 객체로 바꿔라.

Duplicate Observed Data (224)
GUI 컨트롤에서만 사용 가능한 도메인 데이터가 있고 도메인 메소드에서 접근이 필요한 경우, 그 데이터를 도메인 객체로 복사하고 옵저버를 두어 두 데이터를 동기화하라.

Change Unidirectional Association to Bidirectional (232)
각각 서로의 기능을 필요로 하는 클래스가 있는데, 링크가 한쪽 방향으로만 되어 있는 경우, 반대 방향으로 포인터를 추가하고 수정자(modifier)가 양쪽 세트를 모두 업데이트 하게 변경하라.

Change Bidirectional Association to Unidirectional (236)
서로 링크를 가지는 두 개의 클래스에서 한 쪽이 다른 한쪽을 더 이상 필요로 하지 않을 때는 불필요한 링크를 제거하라.

Replace Magic Number with Symbolic Constant (240)
특별한 의미를 가지는 숫자 리터럴이 있으면, 상수를 만들고 의미를 잘 나타내도록 이름을 지은 다음 숫자를 상수로 바꾸어라.

Encapsulate Field (242)
public 필드가 있는 경우, 그 필드를 private으로 만들고 접근자를 제공하라.

Encapsulate Collection (244)
컬렉션(collection)을 리턴하는 메소드가 있으면, 그 메소드가 읽기 전용 뷰를 리턴하도록 만들고 add/remove 메소드를 제공하라.

Replace Record with Data Class (254)
전통적인 프로그래밍 환경에서 레코드 구조에 대한 인터페이스가 필요한 경우, 그 레코드를 위한 데이터 객체를 만들어라.

Replace Type Code with Class (255)
클래스의 동작에 영향을 미치지 않는 숫자로 된 타입 코드가 있으면 숫자를 클래스로 바꾸어라.

Replace Type Code with Subclass (261)
클래스의 동작에 영향을 미치는 변경 불가능하는 타입코드가 있다면, 타입 코드를 서브클래스로 바꾸어라.

Replace Type Code with State/Strategy (265)
클래스의 동작에 영향을 미치는 타입 코드가 있지만 서브클래싱을 할 수 없을 때는 타입 코드를 스테이트(state) 객체로 바꾸어라.

Replace Subclass with Fields (270)
상수 데이터를 리턴하는 메소드만 다른 서브클래스가 있으면, 그 메소드를 수퍼클래스의 필드로 바꾸고 서브클래스를 제거하라.

4. 조건문의 단순화

Decompos Conditional (276)
복잡한 조건문 (if-then-else)이 있는 경우, 조건 then 부분 그리고 else 부분에서 메소드를 추출하라.

Consolidate Conditional Expression (278)
같은 결과를 초래하는 일련의 조건 테스트가 있는 경우, 그것을 하나의 조건식으로 결합하여 뽑아라.

Consolidate Duplicate Conditional Fragments (281)
동일한 코드 조각이 조건문의 모든 분기 안에 있는 경우, 동일한 코드를 조건문 밖으로 옮겨라.

Remove Control Flag (283)
일련의 boolean 식에서 컨트롤 플래그 역할을하는 변수가 있는 경우, break 또는 return을 대신 사용하라.

Replace Nested Conditional with Guard Clauses (288)
메소드가 정상적인 실행 경로를 불명확하게 하는 조건 동작을 가지고 있는 경우, 모든 특별한 경우에 대해서 보호절을 사용하라.

Replace Conditional with Polymorphism (293)
객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우, 조건문의 각 부분을 서브클래스에 있는 오버라이딩 메소드로 옮겨라. 그리고 원래 메소드를 abstract로 만들어라.

Introduce Null Object (298)
null 체크를 반복적으로 하고 있다면, null 값을 null 객체로 대체하라.

Introduce Assertion (306)
코드의 한 부분이 프로그램의 상태에 대하여 어떤 것을 가정하고 있으면, assertion을 써서 가정을 명시되게 만들어라.

5. 메소드 호출의 단순화

Rename Method (313)
메소드의 이름이 그 목적을 드러내지 못하고 있다면, 메소드의 이름을 바꿔라.

Add Parameter (316)
어떤 메소드가 그 메소드를 호출하는 부분에서 더 많은 정보를 필요로 한다면, 이 정보를 넘길 수 있는 객체에 대한 파라미터를 추가하라.

Remove Parameter (318)
파라미터가 메소드 몸체에서 더 이상 사용되지 않는다면, 그 파라미터를 제거하라.

Separate Query from Modifier (320)
값을 리턴할 뿐만 아니라 객체의 상태도 변경하는 메소드를 가지고 있는 경우, 두 개의 메소드를 만들어서 하나는 값을 리턴하는 역할을 하고, 하나는 객체의 상태를 변경하는 역할을 하게 하라.

Parameterize Method (325)
몇몇 메소드가 메소드 몸체에 다른 값을 포함하고 있는 것을 제외하고는 비슷한 일을 하고 있다면, 다른 값을 파라미터로 넘겨 받는 하나의 메소드를 만들어라.

Replace Parameter with Explicit Methods (327)
파라미터의 값에 따라서 다른 코드를 실행하는 메소드가 있다면, 각각의 파라미터 값에 대한 별도의 메소드를 만들어라.

Preserve Whole Object (331)
어떤 객체에서 여러 개의 값을 얻은 다음 메소드를 호출하면서 파라미터로 넘기고 있다면, 대신 그 객체를 파라미터로 넘겨라.

Replace Parameter with Method (335)
객체가 메소드를 호출한 다음, 결과를 다른 메소드에 대한 파라미터로 넘기고 있다. 수신자 또한 이 메소드를 호출할 수 있다면 그 파라미터를 제거하고 수신자가 그 메소드를 호출하도록 하라.

Introduce Parameter Object (339)
자연스럽게 몰려다니는 파라미터 그룹을 가지고 있다면, 그것들을 객체로 바꾸어라.

Remove Setting Method (344)
어떤 필드가 객체 생성시에 값이 정해지고 그 이후에는 변경되지 않아야 한다면, 그 필드 값을 설정하는 모든 메소드를 제거하라.

Hide Method (348)
메소드가 다른 클래스에서 사용되지 않는다면, 그 메소드를 private로 만들어라.

Replace Constructor with Factory Method (350)
객체를 생성할 때 단순히 생성하는 것 이외에 다른 작업도 하고 있다면, 생성자를 팩토리 메소드로 대체하라.

Encapsulate Downcast (355)
메소드가 그 호출부에서 다운캐스트 될 필요가 있는 객체를 리턴하고 있다면 다운캐스트 하는 것을 메소드 안으로 옮겨라.

Replace Error Code with Exception (357)
메소드가 에러를 나타내는 특별한 코드를 가지고 있다면, 대신 예외를 던져라.

Replace Exception with Test (363)
호출부에서 먼저 검사할 수 있는 조건에 대해 예외를 던지고 있다면, 호출부가 먼저 검사하도록 바꿔라.

6. 일반화 다루기

Pull Up Field (368)
두 서브클래스가 동일한 필드를 가지고 있다면, 그 필드를 수퍼클래스로 옮겨라.

Pull Up Method (370)
동일한 일을 하는 메소드를 여러 서브클래스에서 가지고 있다면, 이 메소드를 수퍼클래스로 옮겨라.

Pull Up Constructor Body (373)
서브크래스들이 대부분 동일한 몸체를 가진 생성자를 가지고 있다면, 수퍼클래스에 생성자를 만들고 서브클래스 메소드에서 이것을 호출하라.

Push Down Method (376)
수퍼클래스에 있는 동작이 서브클래스 중 일부에만 관련되어 있다면, 그 동작을 관련된 서브클래스로 옮겨라.

Push Down Field (377)
어떤 필드가 일부 서브클래스에 의해서만 사용되고 있다면, 그 필드를 관련된 서브클래스로 옮겨라.

Extract Subclass (378)
어떤 클래스가 일부 인스턴스에 의해서만 사용되는 기능을 가지고 있다면, 기능의 부분집합을 담당하는 서브클래스를 만들어라.

Extract Superclass (384)
비슷한 메소드와 필드를 가진 두 개의 클래스가 있다면, 수퍼클래스를 만들어서 공통된 메소드와 필드를 수퍼클래스로 옮겨라.

Extract Interface (389)
여러 클라이언트가 한 클래스 인터페이스와 동일한 부분 집합을 사용하고 있거나, 두 클래스가 공통된 인터페이스를 가지는 부분이 있다면, 그 부분 집합을 인터페이스로 뽑아내라.

Collapse Hierarchy (392)
수퍼클래스와 서브클래스가 별로 다르지 않다면, 그것들을 하나로 합쳐라.

Form Template Method (393)
각각의 서브클래스에 동일한 순서로 비슷한 단계를 행하지만 단계가 완전히 같지는 않은 두 메소드가 있다면, 그 단계를 동일한 시그니처를 가진 메소드로 만들어라. 이렇게 하면 원래의 두 메소드는 서로 같아지므로, 수퍼클래스로 올릴 수 있다.

Replace Inheritance with Delegation (401)
서브클래스가 수퍼클래스 인터페이스의 일부분만 사용하거나 또는 데이터를 상속 받고 싶지 않은 경우, 수퍼클래스를 위한 필드를 만들고 메소드들이 수퍼클래스에 위임하도록 변경한 후 상속 관계를 제거한다.

Replace Delegation with Inheritance (404)
위임을 사용하고 있는데 전체 인터페이스에 대해 간단한 위임을 자주 작성하고 있다면, 위임하는 클래스를 대리객체의 서브클래스로 만들어라.




Trackback 0 And Comment 0
prev | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | next