Search
🧮

4. 액션에서 계산 빼내기

SUMMARY - 액션에서 암묵적입력(전역변수)과 출력제거 → 계산으로 바꿀 수 있음 - 계산테스트 코드 적용코드 재사용성에 유리 (+ 부수효과 적음)

기능 요구 사항 및 기존 코드

// Action 전역변수 var shopping_cart = []; var shopping_cart_total = 0; // Action 장바구니에 상품 추가 및 장바구니 금액 업데이트 function add_item_to_cart(name, price) { shopping_cart.push({ name: name, price: price }); calc_cart_total(); } // Action 장바구니 합계 금액 계산 및 화면 업데이트 function calc_cart_total() { shopping_cart_total = 0; for(var i = 0; i < shopping_cart.length; i++) { var item = shopping_cart[i]; shopping_cart_total += item.price; } set_cart_total_dom(); update_shipping_icons(); update_tax_dom(); }
TypeScript
복사
// Action 무료 배송 여부에 따른 아이콘 업데이트 function update_shipping_icons() { var buy_buttons = get_buy_buttons_dom(); for(var i = 0; i < buy_buttons.length; i++) { var button = buy_buttons[i]; var item = button.item; if(item.price + shopping_cart_total >= 20) button.show_free_shipping_icon(); else button.hide_free_shipping_icon(); } } // Action 세금 계산 및 화면 업데이트 function update_tax_dom() { set_tax_dom(shopping_cart_total * 0.10); }
TypeScript
복사

수정 요구 사항

테스트 부서
협업 부서
전역변수에 의존하지 않아야 함
전역 변수에 의존하지 않아야 함
DOM 업데이트와 비지니스 규칙분리 되야 함
DOM 업데이트와 비지니스 규칙분리 되야 함
함수가 결과 값리턴 해야 함
테스트 부서의 어려움
function update_tax_dom() { // BAD 테스트를 위해서 별도의 전역변수 설정이 필요 // BAD 결과값을 테스트하기 위해서는 DOM 접근이 필요 set_tax_dom(shopping_cart_total * 0.10); }
TypeScript
복사
협업 부서의 어려움
function update_shipping_icons() { var buy_buttons = get_buy_buttons_dom(); for(var i = 0; i < buy_buttons.length; i++) { var button = buy_buttons[i]; var item = button.item; // BAD 전역변수에 대한 접근이 필요함 (타 부서는 비지니스 규칙만 필요, DOM 접근 불가) if(item.price + shopping_cart_total >= 20) // BAD DOM이 있는 곳에서만 사용 가능함 (결제팀은 영수증, 배송팀은 운송장 출력 목적) button.show_free_shipping_icon(); else button.hide_free_shipping_icon(); } // BAD 명시적인 리턴값이 없음 }
TypeScript
복사
“부수 효과인 암묵적 입력과 출력을 없애야 한다”
(인자 외 입력값, 리턴값 외의 출력 값이 없어야 함)

단계별 계산 추출 방법

계산 코드추출 새 함수로 만듬
② 새 함수에서 암묵적 입력출력을 찾음
암묵적 입력은 ‘인자’로 암묵적 출력은 ‘리턴값’으로 바꿈

액션에서 계산 빼내기 ① (calc_cart_total)

 BAD
// Action function calc_cart_total() { // BAD 액션 내에 계산이 존재 // BAD 전역변수를 조작함 (암묵적 입력 & 출력) shopping_cart_total = 0; for(var i = 0; i < shopping_cart.length; i++) { var item = shopping_cart[i]; shopping_cart_total += item.price; } set_cart_total_dom(); update_shipping_icons(); update_tax_dom(); }
TypeScript
복사
 GOOD
// Action function calc_cart_total() { // GOOD 액션에서 계산을 분리 shopping_cart_total = calc_total(shopping_cart); set_cart_total_dom(); update_shipping_icons(); update_tax_dom(); } // Calc // GOOD 암묵적 입출력(전역 변수) 대신 인자와 리턴값을 사용 function calc_total(cart) { var total = 0; for(var i = 0; i < cart.length; i++) { var item = cart[i]; total += item.price; } return total; }
TypeScript
복사

액션에서 계산 빼내기 ② (add_item_to_cart)

 BAD
// Action function add_item_to_cart(name, price) { // BAD 액션 내에 계산이 존재 // BAD 전역변수를 조작함 (암묵적 입력 & 출력) shopping_cart.push({ name: name, price: price }); calc_cart_total(); }
TypeScript
복사
 GOOD
// Action function add_item_to_cart(name, price) { // GOOD 액션에서 계산을 분리 shopping_cart = add_item(shopping_cart, name, price); calc_cart_total(); } // Calc function add_item(cart, name, price) { // GOOD 암묵적 입력(전역 변수) 대신 인자로 받음 // GOOD 배열(cart)의 복사본을 만들어 변경 후 리턴 // (불변성을 구현하는 방법 - 카피-온-라이트) var new_cart = cart.slice(); new_cart.push({ name: name, price: price }); return new_cart; }
TypeScript
복사

액션에서 계산 빼내기 ③ (add_item_to_cart)

 BAD
// Action function update_tax_dom() { // BAD 액션 (DOM 변경) 내에 계산이 존재 // BAD 전역변수를 조작함 (암묵적 입력 & 출력) set_tax_dom(shopping_cart_total * 0.10); }
TypeScript
복사
 GOOD
// Action function update_tax_dom() { // GOOD 액션에서 계산을 분리 set_tax_dom(calc_tax(shopping_cart_total)); } // Calc // GOOD 암묵적 입력을 명시적인 인자로 바꿈 function calc_tax(amount) { return amount * 0.10; }
TypeScript
복사

액션에서 계산 빼내기 ④ (update_shipping_icons)

 BAD
// Action function update_shipping_icons() { var buy_buttons = get_buy_buttons_dom(); for(var i = 0; i < buy_buttons.length; i++) { var button = buy_buttons[i]; var item = button.item; // BAD 액션 (DOM 변경) 내에 계산이 존재 // BAD 전역변수를 조작함 (암묵적 입력 & 출력) if(item.price + shopping_cart_total >= 20) button.show_free_shipping_icon(); else button.hide_free_shipping_icon(); } }
TypeScript
복사
 GOOD
// Action function update_shipping_icons() { var buy_buttons = get_buy_buttons_dom(); for(var i = 0; i < buy_buttons.length; i++) { var button = buy_buttons[i]; var item = button.item; // GOOD 액션에서 계산을 분리 if(gets_free_shipping(shopping_cart_total, item.price)) button.show_free_shipping_icon(); else button.hide_free_shipping_icon(); } } // Calc // GOOD 암묵적 입력을 명시적인 인자로 바꿈 function gets_free_shipping(total, item_price) { return item_price + total >= 20; }
TypeScript
복사