함수형 원리로 리팩터링하는 예제 1 - 액션, 계산, 데이터

Raymond Yoo·2023년 12월 11일
0
post-thumbnail

actions-calculations-data

이제는 실제 코드 예시를 리팩터링하는 과정을 직접 보면서
함수형 프로그래밍의 원리를 어떻게
코드에 적용하는지 살펴보자.

함수형 프로그래밍에서는 모든 구성요소를 크게 세 가지로 분류한다.

첫번째 액션(actions)은 부수효과를 일으키는 함수이다.
다른 말로는 비순수 함수(impure function),
순수하지 않은 함수 라고 한다.

두번째 계산(calculations)은 앞에서 언급한
순수 함수(pure function)를 말한다.
순수 함수가 되는 특성은
참조 무결성(referential transparency) 이라고도 한다.

세번째 데이터(data) 는
벌어진 사건들에 대한 객관적 사실을 의미한다.
함수형 프로그래밍에서 모든 로직을 작성하는데 기반이 되는
정보를 담고 있다.

장보기 과정

그런데 actions, calculations, data 로 분류하는 것은
프로그래밍에서 뿐만 아니라 세상 모든 것을 바라볼때
적용할 수 있는 관점이다.

위의 그림처럼 장보기 프로세스를 정리한다고 해보자.
처음에 냉장고를 확인해서 어떤 재고가 남았나 확인하고
운전해서 상점으로 간 후에
필요한 항목들을 구매해서 챙긴 후
다시 운전해서 집으로 돌아오고
사 온 음식을 전부 다 냉장고에 집어넣으면
장보기 활동이 끝난다.

필요한 것 구입하기

이 중에서 장보기 목록을 작성하는 과정을 자세히 살펴보자.
장보기 목록은
내가 필요로 하지만 갖고 있지 못한 항목의 목록이다.
그러므로 (필요한 재고) - (현재 재고) = (장보기 목록) 과 같은
공식을 도출할 수 있다.
이걸 액션, 계산, 데이터라는 관점에서 분류해보면

현재 재고는 데이터이고
필요한 재고도 데이터이고
필요한 재고에서 현재 재고를 빼는 것은 계산이 된다.
장보기 목록도 데이터가 되고
목록에 있는 걸 구입하는건 액션이라고 할 수 있다.

장보기 과정을 분류한 다이어그램

장보기 과정에 포함된 여러가지 요소를
액션, 계산, 데이터로 분류해서
다이어그램을 다시 그려보면 위에 그림과 같이 된다.
냉장고 확인, 운전해서 상점으로 가기는 액션이다.
현재 재고, 필요한 재고는 데이터이고 재고를 빼는 동작은 계산이다.
장보기 목록도 데이터이고
목록에 있는 것을 구입하기, 운전해서 집으로 오기는
액션에 해당한다.

액션, 계산, 데이터가 뭔지 감을 잡았으니까
이제는 간단한 요구조건을 바탕으로
실제 코드에 적용하는 예시를 살펴보자.

기능1 - 장바구니에 담은 물품 가격 총합을 실시간으로 보여줌

MegaMart 라는 e-commerce 서비스가 있다고 해보자.
여기서는 이해를 돕기 위해 장바구니 기능으로
범위를 좁혀서 생각한다.
장바구니 관련해서 첫번째 요구조건은
사용자가 장바구니에 물건을 담거나 빼거나 할때
UI 상에 실시간으로 장바구니 물품 가격의 합을 보여준다는 것이다.

기능2 - 상품 목록에서 어떤걸 장바구니에 추가할때 20 달러 이상이 되면 무료배송 아이콘

두번째 요구조건은
MegaMart 에서는 한번에 20 달러 이상을 구매하면
모든 물품을 무료배송하기로 결정했다.
사용자가 화면에서 상품 목록을 보고 있을때
어떤 물품을 장바구니에 추가했을때
가격 총합이 20 달러 이상이 된다면
해당 물품 옆에 "무료 배송 가능!" 이라는 걸 알려주는
아이콘을 달아서 표시한다.

기능3 - 장바구니 금액 합계가 바뀔때마다 세금을 다시 계산한다

세번째 요구조건은
장바구니에 담은 물품 목록에 변화가 생길때마다
세금을 다시 계산해서 별도의 위치에 저장해두어야 한다.

이렇게 세 가지 요구조건을 기억하면서
하나씩 코드로 구현해보자.

예제코드 링크

첫번째 요구조건 구현 코드

첫번째 요구조건을 구현하면 이렇게 된다.

두번째, 세번재 요구조건 구현 코드

두번째, 세번째 요구조건을 구현하면 이렇게 된다.

액션에서 게산 빼내기 코드

액션은 코드 전체로 퍼져나간다.
어떤 함수에 순수하지 않은 부분,
즉 부수효과(side effect)를 일으키는 부분이 하나라도 있다면
그 함수는 전체가 액션(action)이 된다.

그러므로 액션 함수 또는 비순수 함수에서
계산 영역을 분리해내서 순수 함수로 만드는 것이 좋다.

암묵적 입출력을 명시적 입출력으로 바꾸기 코드

모든 함수는 입력과 출력이 있다.
입력과 출력은 크게
명시적 입출력과 암시적 입출력으로 나눌 수 있다.
함수에 암묵적 입출력 요소가 하나라도 있으면
그 함수는 액션, 즉 비순수 함수가 된다.

명시적 입력은 함수 내부구현에 사용하는 정보를
오직 함수 파라미터를 통해서 얻는 것을 의미하고
명시적 출력은 함수 실행 결과를
오직 함수 반환값을 통해서 얻는 것을 의미한다.

어떤 함수가 명시적 입출력만 이용해서
내부구현을 완료할 수 있어야만
그 함수는 순수 함수가 된다.

최대한 명시적 입출력으로 만들기 코드

암시적 입출력이 있는 부분을 찾아서 명시적 입출력으로 만드는
리팩터링 작업을 조금 더 한다.

입력값을 변경하는 경우, 커피 온 라이트(Copy-On-Write) 적용하기 코드

순수 함수 내에서 입력 파라미터로 받는 어떤 항목을
수정, 변경해야 하는 경우가 있더라도
모든 변수들에 대해서 불변성(immutability)을 유지해야만 한다.
그래야 순수 함수는 그대로 순수 함수로 남을 수 있다.
그걸 가능하게 만드는 방법 중에 하나가 Copy-On-Write 방식이다.

여기서는 입력으로 받은 배열에 항목 하나를 추가해야 하므로
다음과 같은 플로우를 따른다.
(시작) 수정하려는 배열 전체를 복사
-> 새로운 배열을 얻음
-> 새로운 배열에 항목을 하나 추가
-> 새로운 배열을 반환
배열이 아니라 어떤 형태의 변수를 다루더라도
비슷한 원리로 Copy-On-Write 를 구현하면 된다.

함수형 프로그래밍은 전혀 어렵지 않다.
누구라도 당장에
자신의 코드베이스에서 함수형 프로그래밍을 시작할 수 있다.

<참조>
책, 쏙쏙 들어오는 함수형 코딩 3장, 에릭 노먼드, 김은민, 2022
책, 쏙쏙 들어오는 함수형 코딩 4장, 에릭 노먼드, 김은민, 2022
책, 쏙쏙 들어오는 함수형 코딩 5장, 에릭 노먼드, 김은민, 2022
책, 쏙쏙 들어오는 함수형 코딩 6장, 에릭 노먼드, 김은민, 2022

profile
세상에 도움이 되고, 동료에게 도움이 되고, 나에게 도움이 되는 코드를 만들고 싶습니다.

0개의 댓글