Book-Study-For-Developer / Functional-coding-that-fits-easily

쏙쏙 들어오는 함수형 코딩 : 심플한 코드로 복잡한 소프트웨어 길들이기
6 stars 0 forks source link

3장 계산을 여러번 호출하는 것과 계산을 더 분리하는것, 액션과 계산을 분리하는것 에 대한 고민 #13

Open choseonghwan91 opened 1 month ago

choseonghwan91 commented 1 month ago

액션이 전체 코드로 퍼져나가는 코드를 개선해봤습니다.
배운대로 구현하다보니 고민되는 상황에 대해 의견을 나누고 싶습니다.

액션이 전체 코드로 퍼져나가는 코드

const figurePayout = (affiliate) => {
    const owed = affiliate.sales * affiliate.commission;
    if(owed > 100) {
        sendPayout(affiliate.bank_code, owed);
    }
}

const affiliatePayout = (affiliates) => {
    affiliates.forEach((affiliate) => figurePayout(affiliate));
}

const main = (affiliates) => {
    affiliatePayout(affiliates);
}

배운 과정대로 진행

생각해보기

액션, 계산, 데이터로 나눠보기

과정 그려보기

액션 계산 데이터
DB에서 제휴사 가져오기 제휴사 목록
수수료 결정하기 수수료
수수료 보낼 목록 결정하기 수수료 보낼 목록
수수료 보내기

코드로 구현

제휴사(데이터)

const 제휴사 = {
    bank_code: 12,
    sales: 1010,
    commission: 0.1,
}

수수료 결정하기(계산)

const 수수료_결정하기 = (sales, commission) => {
    return sales * commission
}

수수료(데이터)

const 수수료 = 105

수수료 보낼 목록 결정하기(계산)

const 수수료_보낼_목록_결정하기 = (제휴사목록) => {
    return 제휴사목록.filter((제휴사) => {
       const 수수료 = 수수료_결정하기(제휴사.sales, 제휴사.commission);
       return 수수료 > 100;
    })
}

❓ 질문

아래의 액션 중에서 어떤것이 가장 괜찮은지 고민이 됩니다. 액션과 계산은 테스트를 위해 나눌수록 좋으니까 세번째꺼는 안좋은 방법일것 같기도 하고, 어떤게 좋은 방법인지 모르겠습니다. 좋다고 생각하시는 방법이나, 새로운 방법이 있으신가요?!

  1. 수수료_결정하기 함수가 반복해서 두번 실행되는 액션

    const 수수료_보내기 = () => {
    const 제휴사목록 = fetchAffiliatesFromDB();
    const 수수료보낼제휴사목록 = 수수료_보낼_목록_결정하기(제휴사목록);
    수수료보낼제휴사목록.forEach((제휴사) => {
        sendPayout(제휴사.bank_code, 수수료_결정하기(제휴사.sales, 제휴사.commission))
    })
    }
  2. 수수료를 저장하는 계산과 저장한 목록 데이터를 하나 더 만드는 방법

    
    const 수수료_저장하기 = (수수료보낼제휴사목록) => {
    수수료보낼제휴사목록.map((제휴사) => {
        const 수수료 = 수수료_결정하기(제휴사.sales, 제휴사.commission);
        return {...제휴사, sendCommission: 수수료};
    })
    }

const 수수료_보내기 = () => { const 제휴사목록 = fetchAffiliatesFromDB(); const 수수료보낼제휴사목록 = 수수료_보낼_목록_결정하기(제휴사목록); const 수수료저장된목록 = 수수료_저장하기(수수료보낼제휴사목록); 수수료저장된목록.forEach((제휴사) => { sendPayout(제휴사.bank_code, 제휴사.sendCommission); }) }


3. 계산을 액션에 넣어서 `수수료_결정하기` 함수를 한번만 부르기
```js
const 수수료_보내기 = () => {
    const 제휴사목록 = fetchAffiliatesFromDB();
    제휴사목록.forEach((제휴사) => {
        const 수수료 = 수수료_결정하기(제휴사.sales, 제휴사.commission);
        if(수수료 > 100) {
            sendPayout(제휴사.bank_code, 수수료);
        }
    })
}
haryan248 commented 1 month ago

에이스 수환님🔥 책에 없는 예시코드까지 만드시다니 멋있습니다.

아까 스터디시간에 말했듯이 정답은 없어보여요. (3개가 다 좋은 코드 같아요.) 그래도 만약 저였다면..? (2번과 비슷하지만 다르네요.) 저는 owed를 먼저 계산해서 넣어서 한번만 합니다!

type Affiliate = {
   sales: number;
   commission: number;
   bank_code: string;
}
type HasOwedAffiliate = Affiliate & { owed: number };

// 지불해야할 값 기준
const OWED_BOUNDARY = 100;

// owed = 판매량 * 수수료 (계산)
const calcOwed = (sales: number, commission: number) => {
    return sales * commission;
}

// owed 값 추가하기 (계산)
const addOwedToAffiliate = (affiliates: Array<Affiliate>) => {
   return affiliates.map((affiliate) => {
       return { ...affiliate, owed: calcOwed(affiliate.sales, affiliate.commision) };
   });
}

// 지불할 돈이 기준을 넘는 제휴사 알아내기 (계산)
const figureOverOwedAffiliate = (affiliates: Array<HasOwedAffiliate>) => {
    return affiliates.filter((affiliate) => {
        return affiliate.owed > OWED_BOUNDARY;
    });
}

// 최종 액션
const affiliatePayout = (affiliates: Array<Affiliate>) => {
    // 수정해야 할 부분
    const newAffiliates = addOwedToAffiliate(affiliates);
    const filteredAffiliates = figureOverOwedAffiliate(newAffiliates);
    // -----------------------------
    filteredAffiliates.forEach((affiliate) => { 
       sendPayout(affiliate.bank_code, affiliate.owed);
    });
}

근데 이렇게 하다보니.. 순서가 보장되어야 하네요? 조금 더 바꿔보자면..

//  데이터 구조 바꾸기 + 지불해야하는 값 기준 넘는 제휴 알아내기 (계산)
const figurePayout = (affiliates: Array<Affiliate>) => {
    const newAffiliates = addOwedToAffiliate(affiliates);
    const filteredAffiliates = figureOverOwedAffiliate(newAffiliates);
    return filteredAffiliates;
}

// 최종 액션
const affiliatePayout = (affiliates: Array<Affiliate>) => {
    const newAffiliates = figurePayout(affiliates);
    newAffiliates.forEach((affiliate) => { 
       sendPayout(affiliate.bank_code, affiliate.owed);
    });
}

(변수명이나 함수명은 그냥.. 애교로 봐주세요 ㅋㅋㅋ 단어가 어렵네요)

choseonghwan91 commented 1 month ago

너무 깔끔하고 좋은데요??! 먼저 계산해줘서 calcOwed를 한번만 부르고 그 값을 가져다 쓰게 되면 한번만 계산해줘도 되네요! 순서가 필요한걸 한번 더 함수로 묶어주신것도 좋네요! 좋은 의견 감사합니다. ㅋㅋㅋ 제일 깔끔하네요