리팩토링 - 메서드정리

### 참고 문헌
[[리펙토링|Martin Fowler, "리펙토링:코드 품질을 개선하는 객체지향 사고법", 김지원 역, (한빛미디어, 2012)]]

- 리팩토링이 필요한 이유
- 똥 냄새 나는 코드 (코드의 구린내)
- 리펙토링 카탈로그 : 디자인 패턴 같은 거
## 메서드 추출
- 어떤 코드를 그룹으로 묶어도 되겠다고 판단될 때, 
	- 그 코드를 빼내어 목적을 잘 나타내는 직관적 이름의 메서드로 만들자. 
	- 중요한 것은 길이가 아니라 메서드명과 메서드 내용의 의미적 차이라고 할 수 있다.
- 변경 전
```
void printOwing(double amount) {
	printBanner();

	System.out.println("name:" + _name);
	System.out.println("amount:" + amount);
}
```

- 변경 후
```
void printOwing(double amount) {
	printBanner();
	printDetails(amount);
}

void printDetails(double amount) {
	System.out.println("name:" + _name);
	System.out.println("amount:" + amount);
}
```
- 추출하다 보면
	- 지역 변수(임시변수)를 사용하는 경우와 안 하는 경우에 따라 조금 더 신경써야 할 부분이 있다. 
	- 지역 변수가 추출할 메서드에 딸려올 경우 지역변수를 아예 가져올지, 추출한 메서드가 지역변수에 대한 결과를 return 해주어야 할 지 잘 대처하자.
- 메서드 추출 시 추가로 필요한 기법에는
	- 메서드 호출로 전환
	- 메서드 객체로 전환
	- 매개변수로의 값 대입 제거
- 등을 추가로 실시해야 한다. 
## 매서드 내용 직접 삽입
- 매서드 기능이 너무 단순하다면,
	- 그냥 코드를 직접 삽입하고 메서드를 없애자
- 변경 전
```
int getRating() {
	return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
boolean morethanFiveLateDeliveries() {
	return _numberOfLaeDeliveries > 5 ; 
}
```
- 변경 후
```
int getRating() {
	return _numberOfLaeDeliveries > 5 ;
}
```
## 임시변수 내용 직접 삽입
- 한 번 사용되는 임시변수는
	- 그냥 코드를 합쳐버리자
- 변경 전
```
double basePrice = anOrder.basePrice();
return (basePrice > 1000)
```
- 변경 후
```
return (anOrder.basePrice() > 1000)
```
## 임시변수를 메서드 호출로 전환
- 수식의 결과를 저장하는 임시변수가 있을 땐
	- 해당 수식을 통으로 메서드로 추출하고, 임시변수를 메서드로 교체하자.
- 변경 전
```
double basePrice = .quantity * _itemPrice;  
if (basePrice > 1000) 
	return basePrice * 0.95; 
else 
	return basePrice * 0.98
```
- 변경 후
```
if (basePrice() > 1000) 
	return basePrice() * 0.95; 
else 
	return basePrice() * 0.98; 
...

double basePrice() { 
	return .quantity * _itemPrice; 
}
```
## 직관적 임시변수 사용
- 수식이 복잡할 땐
	- 용도에 부합하는 직관적인 이름의 임시변수에 넣어 사용하자
- 변경 전
```
if ( 
	(platform.toUpperCase(). indexOf("MAC") > -1) && 
	(browser.toUpperCase().indexOf("IE") > -1) && 
	wasInitializedO && resize > 0 ) 
{
	// some logic
}
```
- 변경 후
```
final boolean isMacOs = platform.tollpperCase().indexOf("MAC") > -1; 
final boolean isIEBrowser = browser.tolIpperCase().indexOf("IE") > -1; 
final boolean wasResized = resize > 0; 
 
if (isMacOs && isIEBrowser && wasInitializedO && wasResized) {  
	// some logic 
}
```
## 임시변수 분리
- 루프 변수나 값 누적용임시변수가 아닌임시변수에 여러 번 값이 대입될 땐
	- 각 대입마다 다른 임시 변수를 사용하자
- 변경 전
```
double temp = 2 * (_height + .width); 
System.out.printin (temp); 
temp = _height * _width; 
System.out.printin (temp)
```
- 변경 후
```
final double perimeter = 2 * (.height + _width); 
System.out.printin (perimeter); 
final double area = .height * _width; 
System.out.printin (area)
```
## 매개변수로의 값 대입 제거
- 매개변수에 값을 대입하는 코드가 있다면
	- 매개변수를 임시변수에 저장하여 사용하게끔 수정하자
- 전달받은 매개변수에 다른 객체 참조를 대입하면 코드의 명료성도 떨어지고 "값을 통한 전달"과 "참조를 통한 전달"을 혼동하게 되기 때문이다.
- 매개변수에 [final]을 붙여보자
- 변경 전
```
int discount (int inputVal, int quantity, int yearToDate) {  
	if (inputVal > 50) inputVal -= 2
```
- 변경후
```
int discount (int inputVal, int quantity, int yearToDate) {  
	int result = inputVal; 
	if (inputVal > 50) result -= 2
```
## 매서드를 메서드 객체로 전환
- 지역변수 때문에 메서드 추출이 어렵다면,
	- 객체(class)로 추출하자
- 각종 지역변수와 매개변수는 class의 field로 만들어 버리면 된다.
- 그런 다음 앞서 살펴본 기법들을 이용하여 자유롭게 메서드 정리를 해보자
## 알고리즘 전환
- 알고리즘을 더 명확환 것으로 교체를 해야할 땐,
	- 새로운 메서드를 만들기보다는 기존 메서드 내용을 새 알고리즘으로 바꾸자

댓글

이 블로그의 인기 게시물

Session 대신 JWT를 사용하는 이유

VSCode에서의 VIM 단축키와 키보드 구매 가이드

우분투에서 테스트링크(testlink)와 맨티스(mantis)로 테스팅 서버 구성하기