FP
FP 패러다임으로 프로그램이 어떻게 작성되는지에 대한 예시코드다.
UseCase
//shopping
const user = {
name: "Kim",
active: true,
cart: [],
purchase: [],
};
let amzHistory = [];
//Shopping usecase
// 1. Add items to cart
// 2. Add 3% tax to item in cart
// 3. Buy item: cart --> purchase
// 4. Empty cart
// 5. Accept refunds
// 6. Track user history
- 사용자 객체에는 이름, 활성여부, 장바구니, 구매내역이 있다.
- 상품을 장바구니에 담을 수 있다.
- 담긴 상품은 3%의 부가세가 부과된다.
- 장바구니에 담긴 상품을 구매할 수 있다.
- 구매 후에는 장바구니를 비워준다.
- 환불 기능이 있다.
- 사용자의 활동내역을 알 수 있다.
Compose를 사용한 function Flow
const compose =
(f, g) =>
(...args) =>
f(g(...args));
purchaseItem(
emptyCart,
buyItem,
applyTaxToItems,
addItemToCart
)(user, { name: "phone", price: 200 });
function purchaseItem(...fns) {
amzHistory.push(user);
return fns.reduce(compose);
}
구매의 전체적인 흐름을 다루는 purchaseItem함수는
각 흐름에 해당하는 fns를 인자로 받아서 reduce를 이용해 compose를 적용한다.
compose는 두 함수를 순서대로 ...args에 적용시키는 역할을 하며
위 코드에선 emptyCart, buyItem, applyTaxToItems, addItemToCart가
우측부터 순서대로 ...args에 해당하는 (user, {name: "phone", price: 200})에
적용된다.
ex) applyTaxToItems = f(addItemToCart = g(...args)) << first Reduce
buyItem = f(firstReduce = g) << second Reduce
또한 사용자의 로그를 track 하기 위해 amzHistory배열에 각 상태마다의 user객체를 push 한다.
purchase Unit functions
function addItemToCart(user, item) {
const updateCart = user.cart.concat(item);
return Object.assign({}, user, { cart: updateCart });
}
function applyTaxToItems(user) {
const { cart } = user;
const taxRate = 1.3;
const updatedCart = cart.map((item) => {
return { name: item.name, price: item.price * taxRate };
});
return Object.assign({}, user, { cart: updatedCart });
}
function buyItem(user) {
return Object.assign({}, user, { purchase: user.cart });
}
function emptyCart(user) {
return Object.assign({}, user, { cart: [] });
}
위에서부터 차례로
- 장바구니에 상품 담기
- 부가세 3% 과세
- 장바구니 상품 구매
- 장바구니 비우기
를 담당하는 함수들이다.
모든 함수들은 side Effect를 방지하기 위해 Object.assign을 사용해서
새로운 객체를 리턴해준다.
Result
purchaseItem함수에 user객체와 구매할 상품 객체를 인자로 넣어주니
기존 user객체에 없었던 purchase속성에
상품 객체가 담긴 것을 확인할 수 있다.
history
purchase 할 때마다 push 되는 user객체에 따라 사용자 구매 로그를 작성할 수 있다.
자연스럽게 해당 기록을 사용해 refund 요구사항을 충족시킬 수 있다.
add Flow
//if i want to add another func
function refundItem() {
//just go back history of user
}
여기서 코드를 작성하지 않겠지만 만약 환불을 하기 위해서라면
해당 함수는 history에 있는 사용자 객체를 현재 사용자 객체에 대입시키는
함수가 될 것이다.
또는, purchase flow에 새 기능을 추가하고 싶다면 unit function을 작성한 후
purchase의 fns인자에 추가해주기만 한다면
구매 흐름에 해당 unit함수 동작이 추가될 것이다.
전체 코드
//shopping
const user = {
name: "Kim",
active: true,
cart: [],
purchase: [],
};
let amzHistory = [];
//Shopping usecase
// 1. Add items to cart
// 2. Add 3% tax to item in cart
// 3. Buy item: cart --> purchase
// 4. Empty cart
// 5. Accept refunds
// 6. Track user history
const compose =
(f, g) =>
(...args) =>
f(g(...args));
purchaseItem(
emptyCart,
buyItem,
applyTaxToItems,
addItemToCart
)(user, { name: "phone", price: 200 });
function purchaseItem(...fns) {
amzHistory.push(user);
return fns.reduce(compose);
}
function addItemToCart(user, item) {
const updateCart = user.cart.concat(item);
return Object.assign({}, user, { cart: updateCart });
}
function applyTaxToItems(user) {
const { cart } = user;
const taxRate = 1.3;
const updatedCart = cart.map((item) => {
return { name: item.name, price: item.price * taxRate };
});
return Object.assign({}, user, { cart: updatedCart });
}
function buyItem(user) {
return Object.assign({}, user, { purchase: user.cart });
}
function emptyCart(user) {
return Object.assign({}, user, { cart: [] });
}
'Front-end > JavaScript' 카테고리의 다른 글
JS 비동기 1편 - Promise (0) | 2023.03.18 |
---|---|
FP vs OOP (0) | 2023.03.16 |
JS FP 8편 - 함수 합성(Compose, Pipe, Arity) (0) | 2023.03.13 |
JS FP 7편 - Memoization (0) | 2023.03.12 |
JS FP 6편 - 부분 적용 함수(Partial Application) (0) | 2023.03.11 |