programming-study
programming-study copied to clipboard
[oop] 리팩토링
다시 읽어보는 마틴 파울러의 '리팩토링'
켄트 벡의 '모자 두개' 비유법
- 기능 추가와 리팩토링은 별개의 작업이다.
- 리팩토링은 코드를 추가하지 않고 구조만 개선해야 한다. 또한, 테스트 코드는 전혀 수정되지 않아야 한다.
리팩토링이 어떨 때 필요한가?
리팩토링은 틈틈히 하는 것이다.
- 같은 작업을 세 번 이상 할 때
- 기능을 추가할 때
- 버그를 수정할 때
- 코드를 검수할 때
위드 커닝햄 曰, "리팩토링은 대출금이다."
- 대출엔 이자가 따라오듯 리팩토링엔 너무 복잡한 코드로 유지보수와 확장을 위한 별도 비용이 따라온다
- 이자가 적을 땐 견딜 수 있지만 너무 커지만 무리이다.
- 그러므로 리팩토링으로 대출금 일부를 갚는 식으로 관리해야 한다.
리팩토링 설계
- 처음부터 유연한 솔루션을 고려하지말자. 너무나도 막연하다.
- 처음에는 제일 단순한 솔루션을 구축하자. 리팩토링이 필요한 시기에 실시하는 것이 좋다.
단위 테스트와 기능 테스트
- 단위 테스트 목적은 프로그래밍 생산성 향상이다.
- 기능 테스트 목적은 소프트웨어 전반이 제대로 동작하는지 확인 하는 것이다.
※ 너무 많은 테스트를 작성하는 것은 질릴 수 있다. 너무 간단한 코드는 대상에서 제외시킨다.
===================== 방법 =======================
메소드 정리
메소드 추출
- 직관적으로 표현될 수 있는 메소드로 분리
- 명확한 의미를 부여하는 것이 중요
메소드 내용 직접 삽입
- 지나치게 쪼개진 메소드인 경우
임시변수 내용 직접 삽입
임시변수를 메소드 호출로 전환
- 메소드 추출 전에 적용
직관적인 임시변수 사용
- 수식이 길어 이해하기 힘든 메소드
- 하지만, 더 좋은 방법이 있는지 충분히 생각
임시변수 분리
- 임시변수에 여러 번 값이 대입될 때마다 새로운 임시변수를 사용하자.
-
final
를 활용
매개변수로의 값 대입 제거
void aMethod(Object foo) {
foo.modifyInSomeWay(); // 괜찮다.
foo = anotherObject; // 고통과 절망을 안겨줄 것이다. (?)
}
메소드를 메소드 객체로 전환
- 유용한(?) 리팩토링 기법
- 메소드명을 그대로 클래스로 만듬
알고리즘 전환
- 수정이 용이하게 잘게 메소드를 최대한 잘게 쪼갠다.
- 좀 더 변경하기 쉬운 알고리즘으로 교체한다.
객체 간의 기능 이동
메소드 이동
- 의존성이 지나칠 때는 메소드를 옮기는 것이 좋다.
- 기존 메소드는 대리 메소드로 전환하거나 아에 삭제
필드 이동
- 필드가
public
이면 필드 캡슐화 기법을 우선 실시 - getter/setter를 만들자
- 필드 자체를 참조하는 것보다 메소드를 통해 참조하는 것이 옳다 (?)
국소적 상속확장 클래스 사용
-
외부 클래스에 메서드 추가
- ~~하위클래래스화~~
- 래퍼화
배열을 객체로 변환
- 배열을 구성하는 특정 원소가 특별한 의미를 가질 경우 클래스로 랩핑
마법 숫자를 기호 상수로 전환
- 특수한 값을 갖는 숫자
컬랙션 캡슐화
- 컬랙션을 담는 클래스 구성
- 읽기 메소드에는 새로운 컬랙션 반환
레코드를 데이터 클래스로 전환
분류 부호를 하위클래스로 전환
- 추상 팩토리 패턴
abstract class Employee {
// ...
public static create(int type) {
switch(type) {
// ...
}
}
// ...
}
조건문 간결화
여러 겁의 조건문을 감시 절로 전환
- if 헬에서 벗어나자
- 조건은 역순으로 변경해보자
조건문을 재정의로 전환
- 타입에 따라 다른 기능를 실행하는 기능이 존재할 때
- if ~ else, switch 보다는 상속구조를 만드는 것이 좋다.
메소드 호출 간결화
p325