<목차>
0. TL;DR
1. 액션, 계산, 데이터를 나눠서 생각하기
2. 쿠폰 보내기 예제
3. 액션의 다양한 형태
0. TL;DR
- 함수형 프로그래머는 액션, 계산, 데이터를 구분
- 액션: 외부 세계에 영향을 주거나 받는 것 [함수]
- 계산: 입력값을 출력값으로 만듦. 어떤 걸 결정, 계획함 [함수]
- 데이터: 이벤트(일어난 일)에 대해 기록한 사실 [기본 데이터 타입]
- 액션 < 계산 < 데이터 순서로 선호하기
1. 액션, 계산, 데이터를 나눠서 생각하기
- 액션: 외부 세계에 영향을 주거나 받는 것 [함수]
- 실행 시점이나 횟수 혹은 둘 다에 의존
- 함수형 프로그래밍에서 가장 중요!
- 순서(언제 실행되는지), 반복(얼마나 실행되는지)
- 액션을 부르는 함수가 있다면 그 함수도 액션이 됨 ⇒ 액션이 코드 전체로 퍼져나감
- 순수하지 않은 함수, 부수 효과 함수라고도 부름
- 액션을 잘 사용하기 위한 방법
- 가능한 액션을 적게 사용 (액션 대신 계산을 쓸 수 있는지 생각)
- 액션을 가능한 작게 만들기 (액션에서 액션과 관련 없는 코드(결정 or 계획 관련 코드)는 모두 제거)
- 액션이 외부 세계와 상호작용하는 것 제한 (내부: 계산 & 데이터 / 가장 바깥쪽: 액션)
- 액션이 호출 시점에 의존하는 것 제한
- 계산: 입력값을 출력값으로 만듦. 어떤 걸 결정, 계획함 [함수]
- 실행 시점과 횟수에 관계없이 항상 같은 입력값에 대해 같은 출력값 돌려줌
- 계산에는 연산을 담을 수 있음
- 액션보다 계산이 좋은 이유
- 테스트 용이
- 기계적인 분석이 쉬움 (정적 분석에서 자동화된 분석 중요)
- 계산은 조합하기 쉬움 (계산을 조합해 더 큰 계산을 만들 수 있음)
- 계산을 쓰면서 걱정되지 않아도 되는 2가지
- 동시에 실행되는 것
- 과거에 실행됐던 것 or 미래에 실행할 것
- 실행 횟수
- 단점
- 실행해보기 전에 어떤 일이 발생할지 알 수 없음
- 소프트웨어 측면에서 함수는 블랙박스이며, 입력값으로 실행해야 결과를 알 수 있음
- 위 단점이 있으면 계산 or 액션 대신 데이터를 사용하자
- 순수함수, 수학함수라고도 부름
- 데이터: 이벤트(일어난 일)에 대해 기록한 사실 [기본 데이터 타입]
- 변경 불가능함
- 언제나 쉽게 해석할 수 있도록 표현해야 하는 것이 중요
- 데이터 구조로 의미 담을 수 있음
- 장점
- 직렬화된 데이터는 전송하거나 디스크에 저장했다가 읽기 쉬움
- 동일성을 비교하기 쉬움
- 자유로운 해석이 가능하지만, 해석이 늘 반드시 필요하단 게 단점
2. 쿠폰 보내기 예제
사용자 늘리기 이벤트를 구현하라는 요청이 들어왔다고 해보자.
사용자가 친구 10명을 추천하면 더 좋은 쿠폰을 보내려고 한다. 큰 이메일 데이터베이스가 있으며 여기엔 이메일별로 각 사용자가 추천한 친구 수도 기록 중이다.
쿠폰에 대한 정보를 갖고 있는 DB도 있다.
쿠폰 DB는 각 쿠폰에 bad, good, best 같은 등급 정보가 있다. best는 추천을 많이 한 사용자를 위한 쿠폰, good은 모든 사용자에게 전달될 쿠폰, bad는 사용하지 않는 쿠폰이다.
1. 설계하기
액션, 계산, 데이터에 따라 단계를 나누면 위와 같다.
계산을 나누면 구현하기 더 쉬워지지만, 충분히 구현하기 쉽다고 생각되는 시점에 나누는 걸 멈춰야 한다.
2. 구현하기
1. Database에서 가져온 구독자 데이터 ⇒ ‘객체’로 표현
테이블 행은 자바스크립트 객체로 표현할 수 있다.
const subscriber = {
email: 'sample@gmail.com',
rec_count: 16
};
2. 쿠폰 등급 ⇒ ‘문자열’로 표현
const rank1 = 'best';
const rank2 = 'good';
3. 쿠폰 등급 결정 ⇒ ‘함수’
계산: ‘함수’로 구현 (입력값 → 출력값 만듦)
- 입력값: 함수 인자
- 출력값: 함수의 return 값
- 계산 내용: 함수의 본문
// 어떤 구독자가 어떤 등급의 쿠폰을 받을지 결정하는 함수
function subCouponRank(subsciber) { // 입력
if (subscriber.rec_count >= 10) { // 계산
return 'best'; // 출력
} else {
return 'good'; // 출력
}
}
// 이 함수는 명확하고, 테스트하기 쉽고, 재사용할 수 있음
4. DB에서 가져온 쿠폰 데이터 ⇒ ‘객체’로 표현
이제 주어진 등급의 쿠폰 목록만 선택하는 부분을 구현해 보자.
const coupon = {
code: '10PERCENT',
rank: 'bad';
}
5. 특정 등급의 쿠폰 목록을 선택하는 계산 ⇒ ‘함수’
- 입력값: 전체 쿠폰 목록, 선택할 등급
- 출력값: 선택한 등급을 가진 쿠폰 목록
function selectCouponsByRank(coupons, rank) { // 입력
let ret = []; // 빈 배열로 초기화
for(let c = 0; c < coupons.length; c++) { // 모든 쿠폰에 대한 반복
let coupon = coupons[c];
if(coupon.rank === rank) { // 현재 쿠폰이 주어진 등급에 맞으면
ret.push(coupon.code); // 쿠폰 코드를 배열에 넣음
}
return ret; // [출력] 배열을 return
}
}
6. 이메일 ⇒ ‘데이터’
이제 구독자로 이메일을 만드는 부분을 구현해 보자. 다이어그램에서 가장 중요한 부분이다.
보내야 할 이메일을 데이터로 표현해 보자.
이메일 데이터는 보내는 주소, 받는 주소, 제목, 본문을 포함한다. 객체로 표현 가능하다.
// 이 객체는 이메일을 보내기 위한 모든 정보만 담고 있고,
// 어떠한 결정은 담고 있지 않음
const message = {
from: 'newsletter@coupondog.co',
to: 'sample@gmail.com',
subject: 'your weekly coupons inside',
body: 'Here are your coupons ...',
};
7. 구독자가 받을 이메일을 계획하는 계산
- 인자: 구독자, good/best 쿠폰 목록
- 결과값: 이메일 데이터
function emailForSubscriber(subcsriber, goods, bests) { // 입력
let rank = subCouponRank(subscriber);
if (rank === 'best') { // 등급 결정
return { // 이메일 만들어 return
from: 'newsletter@coupondog.co',
to: subscriber.email,
subject: 'Your best weekly coupons inside',
body: 'Here are the best coupons: ' + bests.join(', ')
} else { // rank === 'good'
return { // 이메일 만들어 return
from: 'newsletter@coupondog.co',
to: subscriber.email,
subject: 'Your good weekly coupons inside',
body: 'Here are the good coupons: ' + goods.join(', ')
};
}
}
}
8. 보낼 이메일 목록 준비하기 ⇒ 계산
필요한 코드가 모두 준비되었으니 모든 코드를 합쳐 이메일을 보내는 코드를 구현해 보자.
구독자 목록으로 전체 이메일 목록을 만들어야 한다. 반복문을 사용해서 구현해 보면 다음과 같다.
function emailForSubscribers(subscribers, goods, bests) {
let emails = [];
// 전체 이메일 목록을 만들려면 이메일 만드는 걸 반복하면 됨
for (let s = 0; s < subscribers.length; s++) {
let subscriber = subscribers[s];
let email = emailForSubscriber(subscriber, goods, bests);
emails.push(email);
}
return emails;
}
9. 이메일 보내기는 액션이다.
일반적으로 액션도 계산처럼 함수로 구현한다.
그래서 함수만 보고 계산인지 액션인지 알아보기가 쉽지 않다.
function sendIssue() {
let coupons = fetchCouponsFromDB();
let goodCoupons = selectCouponsByRank(coupons, 'good');
let bestCoupons = selectCouponsByRank(coupons, 'best');
let subscribers = fetchSubscribersFromDB();
let emails = emailsForSubscibers(subscibers, goodCoupons, bestCoupons);
for (let e = 0; e < emails.length; e++) {
let email = emails[e];
emailSystem.send(email);
}
}
3. 액션의 다양한 형태
// 1. 함수 호출
alert('Hello world!'); // 팝업창이 뜨는 것 = 액션
// 2. 메서드 호출
console.log('Hello'); // 콘솔 출력
// 3. 생성자
new Date() // 부르는 시점에 현재 날짜와 시간을 초기화 하기 때문에 호출되는 시점에 따라 다른 값 가짐
// 4. 표현식
// (1) 변수 참조
// (2) y
// (3) 속성 참조
// (4) stack[0]
// (5) user.first_name
// (6) 배열 참조
// ⇒ 공유되고 변경 가능한 변수, 객체, 배열(첫 번째 항목만)이라면 읽는 시점에 따라 값이 다를 수 있음
// 5. 상태
// (1) 값 할당
// (2) z = 3; ⇒ 공유하기 위해 값을 할당했고 변경 가능한 변수라면 다른 코드에 영향을 주기 때문에 액션임
// (3) 속성 삭제
// (4) delete user.first_name; ⇒ 속성을 지우는 것은 다른 코드에 영향을 주기 때문에 액션임
'[Front-end] 개발자 공부' 카테고리의 다른 글
[개발 공부 85일차] 함수형 코딩 | 더 좋은 액션 만들기 (0) | 2024.08.05 |
---|---|
[개발 공부 84일차] ~(Bitwise NOT), ~~, >>> 연산자 (2) | 2024.07.24 |
[개발 공부 81일차] React 공식 문서 | Custom Hook으로 로직 재사용하는 법 (0) | 2024.07.12 |
[개발 공부 80일차] React 공식 문서 | Escape Hatches (4) (0) | 2024.07.11 |
[개발 공부 79일차] React 공식 문서 | Escape Hatches (3) (1) | 2024.07.10 |