|
리팩토링
수정 -> 테스트 -> 수정 -> 테스트... 소프트웨어를 보다 이해하기 쉽고, 수정하기 쉽도록 만드는 것 퍼포먼스 최적화는 종종 코드를 어렵게 만든다. 하지만 필요한 퍼포먼스를 얻기 위해서는 그렇게 해야 한다. 리팩토링은 소프트웨어 디자인을 개선 시킨다. 리팩토링은 소프트웨어를 더 이해하기 쉽게 만든다. 리팩토링은 버그를 찾도록 도와준다. 리팩토링은 프로그램을 빨리 작성하도록 도와준다. 기능을 추가할때 리팩토링을 하라 버그를 수정해야할때 리팩토링을 하라 코드 검토를 할때 리팩토링을 하라 리팩토리링은 그냥 지금 고치면 된다. Extract Method(136) <- 함수를 쪼개는 작업 큰 함수를 작은함수로 쪼개는 작업이다. 객체를 파라미터로 넘기면 call by 레퍼런스로 넘어가기때문에 변경이 되어도 괜찮지만 일반 변수는 그함수에서 변경이 되면 원래 소스의 변수값은 바뀌지 않는다. 이럴때는 리턴값을 써야된다. Inline Method(144) <- 너무 쪼개진 함수를 합치는것 리팩토링은 메소드의 이름의 의도가 잘 나타나게 하는것 너무많이 나누어져있는 메소드를 없애는 것이다. Inline Temp(146) <- 임시변수를 없앰 임시변수가 한번만 초기화되고 한번만 사용된다면 초기화부분을 없애고 바로 대입한다. Replace Temp with Query(147) <- 없앤 임시 변수를 질의 함수로 바꾸는 작업 임시변수를 함수로 바꾸어서 질의 메소드로 바꾸는 작업 지역변수는 메소드의 추출을 어렵게 하기 때문에 많은 변수를 질의 메소드로 바꾸는 것이 좋다. Extract Method를 하기 전에 하는 작업 Introduce Explaining Variable(151) <- 복잡한 로직을 임시변수를 만들어 질의 함수를 만들기 쉽게 수정함(복잡한 로직) 지역변수 때문에 extract Method를 사용하기 어려운 경우 사용한다. 수식이 복잡해져 알아보기 여려울때 임시변수를 만들어 사용하면 수식을 좀더 다루기 쉽게 나누눈데 도움이 된다. Split Temporary Variable(155) <- 임시변수를 한군데서만 사용하게 하나의 임시 변수를 두가지 용도로 사용하면 코드를 보는 사람이 매우 혼란스러울수 있다. Remove Assignments to Parameters(159) 파라미터에 직접 값을 대입하지 않기 위해 임시변수 사용 넘겨 받은 파라미터에 값을 대입하지 않고 임시변수를 만들어 거기에 대입한다. 값이 벼경될수도있고 안될수도있다. 문제의 소지를 없애는 작업이다. Replace Method with Method Object(163) 긴메소드가 있는데 지역변수 대문에 Extract Method를 적용할수 없는 경우 지역변수와 함수 이름으로 새로운 객체를 만들어서 사용 Substitute Algorithm(167) 알고리즘을 보다 명확한 것으로 바꾸고 싶을때 소스를 간단하게 -------------------------------------------------------------------------------------------------------------------------------------------------------------- 메소드의 이동 Move Method(170) 메소드가 자신이 정의된 클래스 보다 다른 클래스의 기능을 더 많이 사용하고 있다면 이 메소드를 가장 많이 사용하고 있는 클래스에 비슷한 몸체를 가진 새로운 메소드를 만들어라. 그리고 이전 메소드는 간단한 위임으로 바꾸거나 완전히 제거하라. Move Field(175) 필드가 자신이 정의된 클래스보다 다른 클래스에 의해서 더 많이 사용되고 있다면 타겟 클래스에 새로운 필드를 만들고 기존 필드를 사용하고 있는 모든 부분을 변경하라. Extract Class(179) 두개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우, 새로운 클래스를 만들어서 관련 있는 필드와 메소드를 예전 클래스에서 새로운 클래스로 옮겨라. Inline Class(184) 클래스가 하는 일이 많지 않은 경우에는 그 클래스에 있는 모든 변수와 메소드를 다른 클래스로 옮기고 그 클래스를 제거하라. Hide Delegate(187) 클리언트가 객체의 위임 클래스를 직접 호출하고 있는 경우 서버에 메소드를 만들어서 대리객체(delegate)를 숨겨라. Remove Middle Man(191) 클래스가 간단한 위임을 너무 많이 하고 있는 겨우에는 클라이언트가 대리객체(delegate)를 직접 호출하도록 하라. Introduce Foreign Method 사용하고 있는 서버 클래스에 부가적인 메소드가 필요하지만 클래스를 수정할 수 없는 경우에는 첫번째 인자로 서버클래스의 인터스턴스를 받는 메소드를 클라이언트에 만들어라. Introduce Local Extension 이장의 내용은 잘몰르겠음 사용하고 있는 서버 클래스에 여러 개의 메소드를 추가할 필요가 있지만 서버 클래스를 수정할 수 없는 경우 필요한 추가 메소드를 포함하는 새로운 클래스를 만들어라 이 확장 클래스를 원래 클래스의 서버 클래스 또는 래퍼(wrapper) 클래스로 만들어라. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 데이터 구성 Self Encapsulate Field(205) 필드에 직접 접근하고 있는데 필드에 대한 결합이 이상해 지면 그 필드에 대한 get/set 메소드를 만들고 항상 이 메소드를 사용하여 필드에 접근하라. 직접 접근과 간접 접근의 사용 지침은 말이 많다. 내가 보기에 적당한 기준은 상속한 클래스에서 슈퍼 필드의 값을 변경해서 사용할때는 간접 접근을 만들고 오버라이드 해서 쓰는게 좀더 명확할꺼 같다. 다른데서 쓰이는 값을이면 간접 접근을 써야 한다. Replace Data Value with Object(209) 추가적인 데이터나 동작을 필요로 하는 데이터 아이템이 있을 때는 데이터 아이템을 객체로 바꾸어라. Change Value to Reference(213) 동일한 인스턴스를 여러개 가지고 있는 클래스가 있고 여러 개의 동일한 인스턴스를 하나의 객체로 바꾸고 싶으면 그 객체를 참조 객체로 바꾸어라. 변경이 그객체를 참조하고 있는 모든 곳으로 전파되기를 바란다. 이 시점이 객체를 참조 객체로 바꾸어야 할 때이다. Change Reference to Value(217) 자고, 불변성(immutable)이고, 관리하기가 어려운 참조 객체(reference object)가 있는 경우 그것을 값 객체(value object)로 바꾸어라. Replace Array with Object(220) 배열의 특정 요소가 다른 뜻을 가지고 있다면 배열을 각각의 요소에 대한 필드를 가지는 개체로 바꿔라. Duplicate Observed Data(224) GUI 컨트롤에서만 사용 가능한 도메인(domain) 데이터가 있고, 도메인 메소드에서 접근이 필요한 경우 그 데이터를 도메인 객체로 복사하고, 옵저버(observer)를 두어 두 데이터를 동기화하라 Change Unidirectional Association to Bidirectional(232) 각각 서로의 기능을 필요로 하는 클래스가 있는데, 링크가 한쪽 방향으로만 되어 있는 경우 반대 방향으로 포인터를 추가하고, 수정자가 양쪽 세트를 모두 업데이트 하게 변경한다. Change Bidirectional Association to Unidirectional(236) 서로 링크를 가지는 두개의 클래스에서 한쪽이 다른 한쪽을 더 이상 필요하지 않을 때는 불필요한 링크를 제거하라. Replace Magic Number with Symbolic Constant(240) 특별한 의미를 가지는 숫자 리터럴이 있으면, 상수를 만들고, 의미를 나타내도록 이름을 지은 다음, 숫자를 상수로 바꾸어라. Encapsulate Field(242) public 필드가 있는 경우 그 필드를 private으로 만들고, 접근자를 제공하라. Encapsulate Collection(244) 컬렉션(Collection)을 리턴하는 메소드가 있으면, 그 메소드가 읽기전용 뷰(read-only view)를 리턴하도록 만들고, add/remove 메소드를 제공하라. Replace Record with Data Class(254) 전통적인 프로그래밍 환경에서의 레코드 구조에 대한 인터페이스가 필요한 경우, 그 레코드를 위한 데이터 객체를 만들어라. Replace Type Code with Subclasses(261) 클래스의 동작에 영향을 미치는 변경 불가능한(immutable) 타입 코드가 있다면, 타입 코드를 서브클래스로 바꾸어라. Replace Type Code with State/Strategy(265) 타입코드가 변경이 된다면 서브클래스를 상속할수가 없다. 클래스의 동작에 영향을 미치는 타입 코드가 있지만 서브클래싱 할 수 없을 때는, 타입 코드를 스테이트 객체로 바꾸어라. Replace Subclass with Fields(270) 상수 데이터를 리턴하는 메소드만 다른 서브 클래스가 있으면 그 메소드를 슈퍼클래스의 필드로 바꾸고 서브클래스를 제거하라. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 조건문의 단순화 Decompose 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) 메소드가 정상적인 실행 결로를 불명확하게 하는 조건 동작을 가지고 있는 경우, 모든 특별한 경우에 대해서 보호절(guard clause)을 사용 하라. Replace Conditional with Polymorphism(293) 객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우, 조건문의 각 부분을 서브클래스에 있는 오버라이딩 메소드(overriding method)로 옮겨라. 그리고 원래 메소드를 abstract로 만들어라. Introduce Null Object(298) 어디에서쓸지? 음... null 체크를 반복적으로 하고 있다면, null값을 null객체로 대체하라. Introduce Assertion(306) 잘몰르겠다. 코드의 한 부분이 프로그램의 상태에 대하여 어떤 것을 가졍하고 있으면, assertion을 써서 가정을 명시되게 (explicit) 만들어라. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 메소드 호출의 단순화 Rename Method(313) 메소드의 이름이 그 목적을 드러내지 못하고 있다면 메소드의 이름을 바꿔라. Add Parameter(316) 어떤 메소드가 그 메소드를 호출하는 부분에서 더 많은 정보를 필요로 한다면, 이 정보를 넘길 수 있는 객체에 대한 파라미터를 추가하라. Remove Parameter(318) 파라미터가 메소드 몸체에서 더 이상 사용되지 않는다면, 그 파라미터를 제거하라. Separate Query from Modifier 값을 리턴할 뿐만 아니라 객체의 상태도 변경하는 메소드를 가지고 있는 경우, 두 개의 메소드를 만들어서 하나는 값을 리턴하는 역활을 하고, 하나는 객체의 상태를 변경하는 역할을 하게 하라. Parameterize Method(325) 몇몇 메소드가 메소드 몸체에 다른 값을 포함하고 있는 것을 제외하고는 비슷한 일을 하고 있다면, 다른 값을 파리미터로 넘겨 받는 하나의 메소드를 만들어라. Replace Parameter with Explicit Methods(327) 파라미터의 값에 따라서 다른 코드를 실행하는 메소드가 있다면, 각각의 파리미터 값에 대한 별도의 메소드를 만들어라. Preserve Whole Object(331) 어떤 객체에서 여러 개의 값을 얻은 다음 메소드를 호출하면서 파라미터로 넘기고 있다면, 대신 그 객체를 파라미터로 넘겨라. Replace Parameter with Method(335) 객체가 메소드를 호출한 다음, 결과를 다른 메소드에 대한 파라미터로 넘기고 있다. 수신자(Receiver - 파라미터를 넘겨 받는 메소드) 또한 이 메소드를 호출할 수 있다면, 그 파라미터를 제거하고 수신자가 그 메소드를 호출 하도록 하라. Introduce Parameter Object(339) 자연스럽게 몰려다니는 파라미터 그룹을 가지고 있다면, 그것을 객체로 바꾸어라. Remove Setting Method(345) 어떤 필드가 객체 생성시에 값이 정해지고 그 이후에는 변경되지 않아야 한다면, 그 필드 값을 설정하는 모든 메소드를 제거하라 Hide Method(348) 메소드가 다른 클래스에서 사용되지 않는다면, 그 메소드를 private으로 만들어라. Replace Constructor with Factory Method(350) 객체를 생성할 때 단순히 성성하는 것 이외에 다른 작업도 하고 있다면, 생성자를 팩토리 메소드로 대체하라. Encapsulate Downcast(355) 메소드가 그 호출부에서 다운캐스트(downcast)될 필요가 있는 객체를 리턴하고 있다면, 다운 캐스트 하는 것을 메소드 안으로 옮겨라. Replace Error Code with Exception(357) 메소드가 에러를 나타내는 특별한 코드를 가지고 있다면, 대신 예외를 던져라. Replace Exception with Test 호출부에서 먼저 검사할 수 있는 조건에 대해 예외를 던지고 있다면, 호출부가 먼저 검사하도록 하꿔라. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 일반화 다루기 다향성을 다루기 위한 부분인거 같다. 상속과 인터페이스등등을 많이 다룬다. 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) 위임을 사용하고 있는데, 전체 인터페이스에 대해 간단한 위임을 자주 작성하고 있다면, 위임 클래스를 대리 객체의 서브 클래스로 만들어라. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 대규모 리팩토링 Tease Apart Inheritance(410) 두가지 작업을 한번에 처리하는 상속 구조가 있는 경우, 두개의 상속 구조를 만들고 하나가 다른 하나를 호출하도록 위음(delegation)을 사용하라. Convert Procedural Design to Objects(416) 절차적 스타일(procedural style)로 작성된 코드가 있다면 데이터 레코드를 객체로 바꾸고 동작을 쪼개서 객체로 옮겨라. Separate Domain from Presentation(418) 도메인 로직을 포함하고 있는 GUI클래스를 가지고 있다면, 도메인 로직을 분리하여 도메인 클래스를 만들어라. Extract Hierarchy(423) 너무 많은 작어을 하거나 또는 부분적으로라도 많은 조건문이 있는 클래스에 대해서는, 각각의 서브클래스가 특정 작업을 담당하도록 클래스의 상속 구조를 만들어라. 출처 : http://nettem.chune.co.kr/
|