액션과 계산, 데이터의 차이
- 3.1 액션과 계산, 데이터를 구분하는 연습
- 3.2 장보기 과정에서 찾아보기
- 3.3 쿠폰 보내기 서비스
- 3.4 액션은 코드 전체로 퍼진다
- 3.5 액션이 퍼지는 것을 막는 방법
액션을 호출하는 함수는 자동으로 액션이 된다 — 이 전염성이야말로 함수형 프로그래밍에서 가장 경계해야 할 거야.
3장은 직접 분류하는 연습 챕터거든. 분류 기준을 다시 정리하면, 액션은 실행 시점이나 횟수에 의존하고 호출할 때마다 결과가 달라질 수 있으며 부수효과가 있는 것, 계산은 입력이 같으면 출력도 항상 같고 몇 번을 호출해도 결과가 동일하며 외부에 영향 없는 것, 데이터는 이벤트에 대한 사실의 기록으로 실행되지 않고 그냥 존재하는 값이야. 여기서 자주 헷갈리는 부분이 있는데, "냉장고에 뭐가 있는지 확인하기"는 계산 같지만 액션이야. 왜? 냉장고 상태는 시간에 따라 바뀌니까. 아침에 확인한 결과와 저녁에 확인한 결과가 다를 수 있거든. 외부 상태를 읽는 것도 액션이라는 점이 중요해.
장보기 프로세스를 단계별로 분류해보면, 냉장고 확인하기는 액션(시점에 따라 결과가 다름), 필요한 것 목록 만들기는 계산(재고와 레시피를 입력하면 항상 같은 목록), 장보기 목록은 데이터(그냥 목록이라는 사실의 기록), 운전해서 마트 가기는 액션(실제 세계를 바꿈), 필요한 것 사기는 액션(세계를 바꾸고 결과가 달라질 수 있음 — 품절 등), 영수증은 데이터(구매 사실의 기록)야. 이 연습의 포인트는 — 같은 프로세스 안에서도 액션, 계산, 데이터가 섞여 있다는 거야. 그리고 우리가 할 일은 여기서 계산과 데이터를 최대한 분리해내는 것이지. 저자가 강조하는 또 하나 — 데이터는 해석이 필요하다는 점이야. 숫자 42가 있으면, 이게 나이인지 가격인지 수량인지는 맥락에 따라 달라.
좀 더 실제 개발에 가까운 예제로 쿠폰 보내기 서비스를 보자. 구독자 중에서 친구를 많이 추천한 사람에게 "베스트 쿠폰"을, 나머지에게 "일반 쿠폰"을 이메일로 보내는 기능이야. 이걸 분류하면, 데이터는 구독자 목록(이메일, 추천 수), 쿠폰 목록(코드, 등급), 이메일 내용이고, 계산은 구독자가 "베스트" 등급인지 판단하기(추천 수 >= 10이면 베스트), 구독자별 적절한 쿠폰 선택하기, 이메일 본문 만들기이고, 액션은 데이터베이스에서 구독자 목록 가져오기, 데이터베이스에서 쿠폰 목록 가져오기, 이메일 보내기야. 핵심 통찰 — 전체 기능 중에서 **실제로 외부 세계와 상호작용하는 부분(액션)**은 얼마 안 돼. 대부분은 데이터를 변환하고 계산하는 부분이야. 이걸 잘 분리하면 테스트하기 쉽고 재사용하기 쉬운 코드가 나와.
여기서 중요한 규칙 하나 — 액션을 호출하는 함수도 액션이 된다. 계산 함수 안에서 sendEmail()을 한 번이라도 호출하면, 그 함수는 더 이상 계산이 아니라 액션이 돼. 이게 전염병처럼 퍼져.
function calculateAndSend(user) { // 이건 액션!
const total = calculate(user); // 이건 계산
sendEmail(user, total); // 이게 액션이니까 전체가 액션
}
액션 하나가 들어가면 그걸 감싸는 함수도 액션, 그걸 감싸는 함수도 액션... 이렇게 액션이 위로 퍼져나가는 것이 함수형 프로그래밍에서 경계해야 할 핵심 문제야.
그래서 어떻게 하냐고? 저자의 답은 명확해. 첫째, 액션에서 계산을 빼내라. 함수 안에 액션과 계산이 섞여 있으면, 계산 부분을 별도 함수로 추출해. 둘째, 액션을 가능한 한 바깥으로 밀어내라. 코드의 가장 바깥 껍질에서만 액션을 실행하고, 안쪽은 전부 계산으로 만들어. 셋째, 데이터를 적극적으로 활용하라. 중간 결과를 데이터로 표현하면, 각 단계를 계산으로 분리할 수 있거든.
정리
3장 읽고 기억할 거 세 가지:
- 액션은 전염된다. 액션을 호출하는 함수도 액션이 됨. 그래서 액션을 최소화하고 격리해야 함
- 분류 연습이 핵심이다. 장보기든 쿠폰 서비스든, 프로세스를 쪼개서 하나하나 액션/계산/데이터로 분류하는 습관이 중요
- 외부 상태를 읽는 것도 액션이다. DB 조회, 현재 시간 확인, 설정값 읽기 — 전부 액션