본문 바로가기
독서/리팩터링

[리팩터링] 챕터06. 기본적인 리팩터링(6 - 3 변수 추출하기)

by 공부하는개미 2022. 5. 29.

 

😀 책에서 기억하고 싶은 내용을 써보세요.

배경

  • 표현식이 너무 복잡해서 이해하기 어려울 때가 있다.
    • 이럴 때 지역 변수를 활용하면 표현식을 쪼개 관리하기 더 쉽게 만들 수 있다.
    • 복잡한 로직을 구성하는 단계마다 이름을 붙일 수 있어서 코드의 목적을 훨씬 명확하게 드러낼 수 있다.
  • 이 과정에서 추가한 변수는 디버깅에 도움된다.
    • 디버거에 중단점을 지정하거나 상태를 출력하는 문장을 추가할 수 있기 때문이다.

 

절차

  1. 추출하려는 표현식에 부작용은 없는지 확인한다.
  2. 불변 변수를 하나 선언하고 이름을 붙일 표현식의 복제본을 대입한다.
  3. 원본 표현식을 새로 만든 변수로 교체한다.
  4. 테스트한다.
  5. 표현식을 여러 곳에서 사용한다면 각각을 새로 만든 변수로 교체한다. 하나 교체할 때마다 테스트 한다.

 

예시

function price(order) {
	// 가격(price) 기본 가격 - 수량 할인 + 배송비
	
	return order.quantity * order.itemPrice -
		Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + 
		Math.min(order.quantity * order.itemPrice * 0.1, 100);
}

 

리팩터링 후 1

function price(order) {
	// 가격(price) 기본 가격 - 수량 할인 + 배송비
	const basePrice = order.quantity * order.itemPrice;
	return order.quantity * order.itemPrice -
		Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + 
		Math.min(order.quantity * order.itemPrice * 0.1, 100);
}

2 이 로직을 이해했다면 기본 가격을 담을 변수를 만들고 적절한 이름을 지어준다.

 

 

리팩터링 후 2

function price(order) {
	// 가격(price) 기본 가격 - 수량 할인 + 배송비
	const basePrice = order.quantity * order.itemPrice;
	return **basePrice** -
		Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + 
		Math.min(order.quantity * order.itemPrice * 0.1, 100);
}

3 이 변수를 실제로 사용해야 하므로 원래 표현식에서 새로 만든 변수에 해당하는 부분을 교체한다.

 

 

리팩터링 후 3

function price(order) {
	// 가격(price) 기본 가격 - 수량 할인 + 배송비
	const basePrice = order.quantity * order.itemPrice;
	return **basePrice** -
		Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + 
		Math.min(**basePrice** * 0.1, 100);
}

5 방금 교체한 표현식이 쓰이는 부분이 더 있다면 마찬가지로 새 변수를 사용하도록 수정한다.

 

 

최종 리팩터링 완료

const basePrice = order.quantity * order.itemPrice;
const quantityDiscount = Math.max(0, order.quantity - 500)
													* order.itemPrice * 0.05;
const shipping = Math.min(basePrice * 0.1, 100);
return basePrice - quantityDiscount + shipping;

2 ~ 5 마지막으로 수량 할인, 배송비도 똑같이 처리한다. 다 수정했다면 주석은 지워도 된다.

 

 

예시: 클래스 안에서

class Order {
	constructor(aRecord) {
		this._data = aRecord;
	}
	
	get quantity() {return this._data.quantity;}
	get itemPrice() {return this._data.itemPrice;}
	
	get price() {
		return this.quantity * this.itemPrice - 
			Math.max(0, this.quantity - 500 * this.itemPrice * 0.05 +
			Math.min(this.quantity * this.itemPrice * 0.1, 100);
	}
}

이번에도 추출하려는 이름은 같다. 하지만 그 이름이 가격을 계산하는 price() 메서드의 범위를 넘어.

주문을 표현하는 Order 클래스 전체에 적용된다. 이처럼 클래스 전체에 영향을 줄 때 저자는 변수가 아닌 메서드로 추출하는 편이라고 한다.

 

 

리팩터링 후

class Order {
	constructor(aRecord) {
		this._data = aRecord;
	}
	
	get quantity() {return this._data.quantity;}
	get itemPrice() {return this._data.itemPrice;}
	
	get price() {
		return this.basePrice - this.quantityDiscount + this.shipping;
	}

	get basePrice()        {return this.quantity * this.itemPrice;}
	get quantityDiscount() {return Math.max(0, this.quantity - 500) * this.itemPrice * 0.05;}
	get shipping()         {return Math.min(this.basePrice * 0.1, 100);}
}
  • 여기서 객체의 엄청난 장점을 볼 수 있다.
    • 객체는 특정 로직과 데이터를 외부와 공유하려 할 때 공유할 정보를 설명해주는 적당한 크기의 문맥이 되어준다.
    • 덩치가 큰 클래스에서 공통 동작을 별도 이름으로 뽑아내서 추상화해두면 그 객체를 다룰 때 쉽게 활용할 수 있어서 매우 유용하다.

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  • 확실히 변수로 추출을 하면 좀 더 직관적으로 볼 수 있다고 느꼈습니다.
  • 상당히 간결하지만 한줄에 모든걸 담은 로직은 가독성이 낮았습니다.
  • 결국에 변수명을 잘 지어야 빛을 발하는 리팩터링 방법 같습니다.

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.

  • 추상화의 정의는 책으로 여러번 봤지만 실제로 활용하는 방법을 아직 잘 모르겠습니다.

 

 

반응형