😀 책에서 기억하고 싶은 내용을 써보세요.
배경
- 표현식이 너무 복잡해서 이해하기 어려울 때가 있다.
- 이럴 때 지역 변수를 활용하면 표현식을 쪼개 관리하기 더 쉽게 만들 수 있다.
- 복잡한 로직을 구성하는 단계마다 이름을 붙일 수 있어서 코드의 목적을 훨씬 명확하게 드러낼 수 있다.
- 이 과정에서 추가한 변수는 디버깅에 도움된다.
- 디버거에 중단점을 지정하거나 상태를 출력하는 문장을 추가할 수 있기 때문이다.
절차
- 추출하려는 표현식에 부작용은 없는지 확인한다.
- 불변 변수를 하나 선언하고 이름을 붙일 표현식의 복제본을 대입한다.
- 원본 표현식을 새로 만든 변수로 교체한다.
- 테스트한다.
- 표현식을 여러 곳에서 사용한다면 각각을 새로 만든 변수로 교체한다. 하나 교체할 때마다 테스트 한다.
예시
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);}
}
- 여기서 객체의 엄청난 장점을 볼 수 있다.
- 객체는 특정 로직과 데이터를 외부와 공유하려 할 때 공유할 정보를 설명해주는 적당한 크기의 문맥이 되어준다.
- 덩치가 큰 클래스에서 공통 동작을 별도 이름으로 뽑아내서 추상화해두면 그 객체를 다룰 때 쉽게 활용할 수 있어서 매우 유용하다.
🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.
- 확실히 변수로 추출을 하면 좀 더 직관적으로 볼 수 있다고 느꼈습니다.
- 상당히 간결하지만 한줄에 모든걸 담은 로직은 가독성이 낮았습니다.
- 결국에 변수명을 잘 지어야 빛을 발하는 리팩터링 방법 같습니다.
🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.
- 추상화의 정의는 책으로 여러번 봤지만 실제로 활용하는 방법을 아직 잘 모르겠습니다.
반응형