mingg IT

[함수형 프로그래밍] 5장 더 좋은 액션 만들기 본문

FrontEnd

[함수형 프로그래밍] 5장 더 좋은 액션 만들기

mingg123 2023. 10. 9. 16:54

1장 부터 읽었을때 가장 인상깊고 재밌었던 장이다.

함수 내 코드를 분리할때 어떤 기준으로 나눌지 애매한 경우가 많았는데 비즈니스 규칙, 계산, 액션 등으로 나누는 기준을 알려줌 

 

수정 전 (4장 코드)

var shopping_cart = [];
var shopoing_cart_total = 0;

function add_item_to_cart(name, price) {
	shopping_cart = add_item(shopping_cart, name, price);
	calc_cart_total();
}

function calc_cart_total() {
	shopping_cart_total = calc_total(shopping_cart);
	set_cart_total_dom();
	update_shipping_icons();
	update_tax_dom();
}

function update_shipping_icons() {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;

		if (gets_free_shipping(shopping_cart_total, item.price)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}

function update_tax_dom() {
	set_tax_dom(calc_tsx(shopoing_cart_total));
}

function add_item(cart, name, price) {
	var new_cart = cart.slice();
	new_cart.push({
		name: name,
		price: price,
	});
	return new_cart;
}

function calc_total(cart) {
	var total = 0;
	for (var i = 0; i < cart.length; i++) {
		var item = cart[i];
		total += item.price;
	}
	return total;
}

function gets_free_shipping(total, item_price) {
	return item_price + total >= 20;
}

function calc_tax(amount) {
	return amount * 0.1;
}

 

비즈니스 요구사항 변경됨

 

장바구니에 담긴 제품을 주문할 때 무료배송인지 판단함

var shopping_cart = [];
var shopoing_cart_total = 0;

function add_item_to_cart(name, price) {
	shopping_cart = add_item(shopping_cart, name, price);
	calc_cart_total();
}

function calc_cart_total() {
	shopping_cart_total = calc_total(shopping_cart);
	set_cart_total_dom();
	update_shipping_icons();
	update_tax_dom();
}

function update_shipping_icons() {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;
        // 수정된 부분 
		var new_cart = add_item(shopping_cart, item.name, item.price);
		if (gets_free_shipping(new_cart)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}

function update_tax_dom() {
	set_tax_dom(calc_tsx(shopoing_cart_total));
}

function add_item(cart, name, price) {
	var new_cart = cart.slice();
	new_cart.push({
		name: name,
		price: price,
	});
	return new_cart;
}

function calc_total(cart) {
	var total = 0;
	for (var i = 0; i < cart.length; i++) {
		var item = cart[i];
		total += item.price;
	}
	return total;
}

// 수정된 부분 
function gets_free_shipping(cart) {
	return calc_total(cart) >= 20;
}

function calc_tax(amount) {
	return amount * 0.1;
}

 

함수형 프로그래밍 원칙

 

  • 암묵적 입력과 출력은 적을수록 좋다
  • 설계는 엉켜있는 코드를 푸는 것이다 (재사용, 유지보수, 테스트 하기 쉽도록) 
  •  

 

암묵적 입력과 출력을 줄인 결과

// var shopping_cart = [];
// var shopoing_cart_total = 0;

// C: cart에 대한 동작
// I: item에 대한 동작
// B: 비즈니스 규칙
function add_item_to_cart(name, price) {
	shopping_cart = add_item(shopping_cart, name, price);
	// calc_cart_total(shopping_cart);

	var total = calc_total(shopping_cart);
	set_cart_total_dom();
	update_shipping_icons(shopping_cart);
	update_tax_dom(total);
}

function calc_cart_total(cart) {
	var total = calc_total(cart);
	set_cart_total_dom();
	update_shipping_icons(cart);
	update_tax_dom(total);
}

// c, i , b
function update_shipping_icons(cart) {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;
		var new_cart = add_item(cart, item.name, item.price);
		if (gets_free_shipping(new_cart)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}

function update_tax_dom(total) {
	set_tax_dom(calc_tsx(total));
}

// c, i
function add_item(cart, name, price) {
	var new_cart = cart.slice();
	new_cart.push({
		name: name,
		price: price,
	});
	return new_cart;
}

// c, i, b
function calc_total(cart) {
	var total = 0;
	for (var i = 0; i < cart.length; i++) {
		var item = cart[i];
		total += item.price;
	}
	return total;
}

// b

function gets_free_shipping(cart) {
	return calc_total(cart) >= 20;
}

// b
function calc_tax(amount) {
	return amount * 0.1;
}
  • 전역변수를 제거하고
  • calc_cart_total 함수가 하는일이 너무 많아서 calc_cart_total함수 내에 있는 add_item_to_cart 함수로 옮겨줌 
  • cart, item, 비즈니스 규칙에 관한 부분은 분리하기 시작해야함 

 

 

add_item 함수 분리하여 좋은 설계 만들기

// c, i , b
function update_shipping_icons(cart) {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;
		var new_cart = add_item(cart, make_cart_item(item.name, item.price));
		if (gets_free_shipping(new_cart)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}


// c
function add_item(cart, item) {
	var new_cart = cart.slice();
	new_cart.push(item);
	return new_cart;
}

function make_cart_item(name, price) {
	return {
		name: name,
		price: price,
	};
}
  • 기존 add_item은 cart, item 구조 모두를 알고있어야 했음
  • make_cart_item에서 아이템에 대한 구조를 알도록 한뒤, add_item은 item의 구조를 알 필요없도록 분리함 

 

add_item -> add_element_last 공통 유틸로 변경

// c, i , b
function update_shipping_icons(cart) {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;
		var new_cart = add_item(cart, make_cart_item(item.name, item.price));
		if (gets_free_shipping(new_cart)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}

function add_item(cart, item) {
	return add_element_last(cart, item);
}

function add_element_last(array, elem) {
	var new_array = array.slice();
	new_array.push(elem);
	return new_array;
}

function make_cart_item(name, price) {
	return {
		name: name,
		price: price,
	};
}
  • 이제부터 add_item 카피-온-라이트를 사용해 배열에 항목을 추가하는 함수가 되었기 때문에 은 공통 유틸로 관리함

 

중간 점검 코드

// var shopping_cart = [];
// var shopoing_cart_total = 0;

// C: cart에 대한 동작
// I: item에 대한 동작
// B: 비즈니스 규칙
// A: 배열 유틸
function add_item_to_cart(name, price) {
	shopping_cart = add_item(shopping_cart, make_cart_item(name, price));
	// calc_cart_total(shopping_cart);

	var total = calc_total(shopping_cart);
	set_cart_total_dom();
	update_shipping_icons(shopping_cart);
	update_tax_dom(total);
}

function calc_cart_total(cart) {
	var total = calc_total(cart);
	set_cart_total_dom();
	update_shipping_icons(cart);
	update_tax_dom(total);
}

// c, i , b
function update_shipping_icons(cart) {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;
		var new_cart = add_item(cart, make_cart_item(item.name, item.price));
		if (gets_free_shipping(new_cart)) button.show_free_shipping_icon();
		else button.hide_free_shipping_icon();
	}
}

// A
function add_item(cart, item) {
	return add_element_last(cart, item);
}

// A
function add_element_last(array, elem) {
	var new_array = array.slice();
	new_array.push(elem);
	return new_array;
}

// I

function make_cart_item(name, price) {
	return {
		name: name,
		price: price,
	};
}

function update_tax_dom(total) {
	set_tax_dom(calc_tsx(total));
}

// c, i, b
function calc_total(cart) {
	var total = 0;
	for (var i = 0; i < cart.length; i++) {
		var item = cart[i];
		total += item.price;
	}
	return total;
}

// b
function gets_free_shipping(cart) {
	return calc_total(cart) >= 20;
}

// b
function calc_tax(amount) {
	return amount * 0.1;
}
  • 배열 유틸리티 관련된 A를 주석으로 추가함

 

update_shipping_icons 수정

// c, i , b
function update_shipping_icons(cart) {
	var buttons = get_buy_buttons_dom();
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		var item = button.item;

		var new_cart = add_item(cart, make_cart_item(item.name, item.price));
		var hasFreeShipping = gets_free_shipping_with_item(new_cart, item);
		set_free_shipping_icon(hasFreeShipping);
	}
}

function gets_free_shipping_with_item(cart, item) {
	var new_cart = add_item(cart, item);
	return gets_free_shipping(new_cart);
}

function set_free_shipping_icon(button, isShown) {
	if (isShown) button.show_free_shipping_icon;
	else button.hide_free_shipping_icon;
}
  • 너무 많은 기능을 하는 update_shipping_icons를 수정 
  • 아이템으로 카트를 계산하는 부분, 버튼을 보여주는 부분을 각각 나눔 

 

요점

  • 일반적으로 암묵적 입력과 출력은 인자와 리턴값으로 바꿔 없에는 것이 좋다
  • 설계는 엉켜있는 것을 푸는 것임. 풀려있는 것은 언제든지 다시 합칠 수 있음
  • 엉켜있는 것을 풀어 각 함수가 하나의 일만 하도록 하면, 개념을 중심으로 쉽계 구성 할 수 있음 
  • 8장에 다시 설계에 대한 내용을 살펴볼 예정 
  • 장바구니기능에 버그가 숨어있다함.. 

 

Comments