우석
액션에서 계산 빼내기
// 예시 1
function calc_cart_total() {
shopping_cart_total = 0;
for (var i = 0; i < shipping_cart.length; i++) {
var item = shipping_cart[i];
shopping_cart_total += item.price;
}
set_cart_total_dom();
update_shipping_icons();
update_tax_dom();
}
// 예시 2
function add_item_to_cart(name, price) {
shopping_cart.push({
name: name,
price: price
})
}
위 2개의 메서드에서 액션을 빼내보자
1. 함수 추출하기
// 예시 1
function calc_total() {
shopping_cart_total = 0;
for (var i = 0; i < shipping_cart.length; i++) {
var item = shipping_cart[i];
shopping_cart_total += item.price;
}
}
// 예시 2
function add_item(name, price) {
shopping_cart.push({
name: name,
price: price
})
}
- 액션에서 계산으로 뺄 수 있는 단위로 메서드를 생성한다.
- 이후 기존 로직에서 새로 생성한 메서드를 호출하도록 변경한다.
2. 암묵적 입력 찾고 명시적으로 변경하기
// 예시 1
function calc_total(cart) {
var total = 0;
for (var i = 0; i < cart.length; i++) {
var item = cart[i];
total += item.price;
}
return total;
}
// 예시 2
function add_item(cart, name, price) {
cart.push({
name: name,
price: price
})
}
- 입력에는 암묵적 입력과 명시적 입력이 있다.
- 명시적 입력은 매개변수로 받은 입력을 뜻하고 나머지는 모두 암묵적 입력이다.
- 암묵적 입력은 메서드를 액션으로 만들기 때문에 암묵적 입력으로 변경한다.
3. 암묵적 출력 찾고 명시적으로 변경하기
// 예시 2
function add_item(cart, name, price) {
var new_cart = cart.slice();
new_cart.push({
name: name,
price: price
})
return new_cart;
}
- 리턴값을 제외한 모든 출력은 암묵적 출력이다.
- 암묵적 출력을 찾아 명시적 출력으로 변경해야 계산이 된다.
- 여기서 입력을 받은 cart를 복사해서 사용한 이유는 무엇일까?
- 책에서는 질문만 하고 답을 알려주지는 않았지만 추측해보자면 인자로 받은 cart를 그대로 사용하면 외부의 변경에 의해 반환값이 달라질 수도 있다.
- 즉, 메서드 호출 시점에 의존하기 때문에 계산이 아니라 액션이 된다.
- 사실 위 방식도 slice()가 호출되기 이전 찰나에 외부 동작에 의해 결과가 바뀔 수도 있지만 그 시간을 미미하게 만든다는데 의미가 있는 것 같다.
만혁
액션에서 계산 빼내기
테스트하기 쉽게 만들기
테스트를 쉽게하려면 다음 조건이 필요하다.
- DOM 업데이트와 비즈니스 규칙은 분리 되어야 한다.
- 전역변수가 없어야 한다.
재사용하기 쉽게 만들기
- 전역변수에 의존하지 않아야 한다.
- DOM을 사용할 수 있는 곳에서 실행한다고 가정하면 ㅏㄴ된다.
- 함수가 결과값을 리턴해야 한다.
액션과 계산, 데이터 구분하기
액션은 코드 전체로 퍼지기 때문에 어떤 함수안에 액션이 하나만 있어도
그 함수 전체가 액션이 된다.
함수에는 입력과 출력이 있다
입력은 함수가 계산을 하기 위한 외부 정보이며, 출력은 함수 밖으로 나오는 정보나 어떤 동작이다.
함수를 호출하는 이유는 결과가 필요하기 때문이다.
그리고 원하는 결과를 얻으려면 입력이 필요하다.
입력과 출력은 명시적이거나 암묵적일 수 있다.
let total = 0;
function add_to_total(amount) { // 인자는 명시적 입력
console.log( // 콘솔에 찍는것은 암묵적 출력
`old total ${total}` // 전역변수를 읽는것은 암묵적 입력
);
total += total; // 전역변수를 바꾸는것은 암묵적 출력
return total; // 리턴값은 명시적 출력
}
함수에 암묵적 입력과 출력이 있으면 액션이 된다.
함수에서 암묵적 입력과 출력을 없애면 계산이 된다.
암묵적 입력은 함수의 인자로 바꾸고, 암묵적 출력은 함수의 리턴값으로 변경하면 된다.
테스트와 재사용성은 입출력과 관련있다.
- DOM 업데이트와 비즈니스 규칙은 분리되어야 한다.
- 전역변수가 없어야 한다.
- 전역변수에 의존하지 않아야 한다.
- DOM 을 사용할수 있는곳에서 실행된다고 가정하면 안된다.
- 함수가 결과값을 리턴해야 한다.
액션에서 또 다른 계산 빼내기
function add_item_to_cart(name, price) {
// 이 코드를 새 함수로 빼낸다
shopping_cart.push({
name,
price
})
calc_cart_total();
}
function add_item_to_cart(name, price) {
add_item(name, price); // 빼낸 부분은 새로 만든 함수를 호출하도록 변경
calc_cart_total();
}
function add_item(name, price) {
shopping_cart.push({
name,
price
})
}
암묵적 입력을 없앤 코드
// 암묵적 입력을 없앤 코드
function add_item_to_cart(name, price) {
add_item(shopping_cart, name, price);
calc_cart_total();
}
function add_item(cart, name, price) { // cart 인자를 추가하여 명시적 입력으로 수정
cart.push({name, price});
}
암묵적 출력을 없앤 코드
// 암묵적 출력을 없앤 코드
function add_item_to_cart(name, price) {
shopping_cart = add_item(shopping_cart, name, price); // 리턴값을 받아 전역변수에 할당
calc_cart_total();
}
function add_item(cart, name, price) {
const new_cart = cart.slice(); // 복사본을 만들어 지역변수에 할당
new_cart.push({name, price}); // 복사본을 변경
return new_cart; // 복사본을 리턴
}
연습 문제
함수에서 세금을 계산하는 부분을 추출해라
// as-is
function update_tax_dom() {
set_tax_dom(shopping_cart_total * 0.10);
}
// to-be
function update_tax_dom() {
set_tax_dom(calc_tax(shopping_cart_total))
}
function calc_tax(total) {
const tax_ratio = 0.10;
return total * tax_ratio;
}
함수에서 계산을 추출해 봐라
// as-is
function update_shipping_icons() {
const buy_buttons = get_buy_buttons_dom();
for (const i = 0 ; i < buy_buttons.length ; i++) {
const button = buy_buttons[i];
const item = button.item;
if (item.price + shopping_cart_total >= 20) { // 비즈니스 규칙
button.show_free_shipping_icon();
} else {
button.hide_shipping_icon();
}
}
}
// to-be
function update_shipping_icons() {
const buy_buttons = get_buy_buttons_dom();
for (const i = 0 ; i < buy_buttons.length ; i++) {
const button = buy_buttons[i];
const item = button.item;
if (item.price + shopping_cart_total >= 20) { // 비즈니스 규칙
button.show_free_shipping_icon();
} else {
button.hide_shipping_icon();
}
}
}
function isFreeShipping(price, total) {
const free_shipping_count = 20;
return price + total >= free_shipping_count;
}
회독 후기
- 액션에서 계산을 빼내는 작업은 쉬워보이지만 어렵다