함수형 프로그래밍과 액션, 계산, 데이터

Mincho·2023년 8월 27일
0
post-thumbnail

책에서의 함수형 프로그래밍에 대한 정의

 이전글에서 살펴볼 당시 함수형 프로그래밍은 실무적인 내용보다는 학문적인 요소로 다뤄지는 경우가 대부분이였습니다. 그렇기 때문에 이 도서에서는 함수형 프로그래밍을 실무에서도 사용가능하도록 서술한 부분이있습니다. 위키피디아에서는 함수형 프로그래밍을 이렇게 정의하고 있습니다.

  1. 수학 함수를 사용하고 부수 효과를 피하는 프로그래밍 패러다임
  2. 부수 효과가없는 순수함수만 사용하는 프로그래밍 스타일

 여기서 부수효과란 함수 리턴값이외에 모든 일을 하는 것을 의미합니다. 제가 만든 예제를 통해서 부수 효과에 대해 자세히 알아보도록 하겠습니다.

const initial = 0;

const add = () => {
  ++initial
}

add()

console.log(initial) // 1

다음과 같이 파라미터를 받지 않고 외부 전역변수 initial의 값을 변경시키고 있는 것을 확인 할 수 있습니다. 위와 같은 구조에서는 단순한 구조이기 때문에 문제가 없을 수 있지만 여러 기능들이 추가됨에 따라 의도하지 않게 외부에 있는 값들을 변경시켜 큰 혼란을 불러일으킬 수 있게 됩니다. 이 때문에 함수 인자에만 의존하여 결과값을 리턴하는 순수함수를 사용하여 다른 개발자가 보더라도 다루고 이해하기 쉽게 하는 것이 현명합니다.



액션과 계산 데이터

 함수형 프로그래밍을 다룰 때에는 위의 개념들에 대해서 알고 구분할 줄 알아야합니다. 글쓴이는 이에 대해 이렇게 분류하고 설명하고 있습니다.

  1. 액션 : 실행 시점이나 횟수 또는 둘 다에 의존합니다.
  2. 계산 : 입력값으로 출력값을 만드는 행위입니다. 같은 입력값은 언제나 값은 결과를 반환합니다.
  3. 데이터 : 이벤트에 대해 기록한 사실이며 다른 코드만큼 복잡하지 않고 데이터 자료 자체로 의미가 있습니다.

 우선적으로 함수형 프로그램을 진행 할 때 위의 3가지 개념에 대해 구분하는 것이 일입니다.

액션

 실행 시점과 횟수에 의존하는 부수 효과를 다루는 함수라고 설명할 수 있습니다. 그렇기 때문에 액션은 호출 시점과 횟수에 의존하게 됩니다.

예를 들어 우리가 필요한 음식을 구매 전에 제고를 확인하기 위해 냉장고를 확인하는 행동은 액션입니다. 왜냐하면 냉장고를 언제 확인하냐는 시점에 따라 냉장고의 제고들이 각각 다르기 때문입니다.

계산

 이와 반대로 계산은 항상 같은 결과를 반환하여 부수효과를 다루지 않습니다.

냉장고의 제고를 채우기 위해 물건을 사고 산 물건을 냉장고에 채우는 행위는 부수효과를 일으키지 않고 그저 입력값으로 같은 결과값을 주기 때문입니다.

데이터

  데이터 같은 경우 사실 자료 그 자체입니다.

냉장고에 있는 제고, 구매한 물품들은 그냥 그 데이터 자체입니다.

이러한 모든 경우를 다룰 때에 액션,계산 그리고 데이터를 분류하고 적용하는 것이 가장 큰 과제라고 볼 수 있습니다. 그러면 이러한 것을 구분하는 연습부터 해보겠습니다.



네이밍 규칙과 컨벤션

 연습전에 액션, 계산 그리고 데이터를 구분하는 작업에 앞서서 네이밍 규칙과 컨벤션에 대해 알아보겠습니다. 이 부분들은 이 책에 나와있지 않지만 기본적으로 잡고 나가는데에 좋은 것 같아 짚고 넘어가는 것이 함수형 프로그래밍에 대해 더 다가갈수 있다고 생각했습니다. 물론 저의 경우입니다.

함수 네이밍

 저는 함수를 네이밍 할 때 조금더 길더라도 누구나 이해할 수 있도록 직관적으로 네이밍하는 편입니다. 다음과 같은 예시를 통해 알아보겠습니다.

add(a,b) / init() / fetchData()

 위와 같은 함수는 다른 개발자가 봤을 때 어떤 역할을 하는지 알기가 힘듭니다. add는 a,b를 받아서 더하는 함수구나, init은 초기화해주는 함수구나, fetchData는 api로부터 fetch해오는 함수구나 정도로 이해할 수 있지만 본질적으로 add는 뭘 더해주는 거지?, init은 뭘 초기화 해주는 거야?, fetchData는 어떤 api 리소스를 가져와주는 거지?라는 물음을 가지게 됩니다.

 이를 명확하게 이해할 수 있도록 바꿔봅시다.

addLastFinalExamMathScore(a,b) / initTotalExamData() / fetchWholeStudentScore()

 위와 같이 변수명 네이밍을 진행해보았습니다. 조금 변수명이 길어지더라도 함수가 하는 역할에 대해서 좀 더 누구나 알아볼 수 있도록 명확해졌습니다. 또한 카멜케이스를 적용하여 변수를 알아보기 쉬워졌습니다.(컴포넌트를 구성할때는 앞에는 대문자를 사용하는 파스칼케이스를 사용했습니다.)

  또한 eventHandler, react-query에서 mutation에서 파생된 함수는 함수 네이밍에 있어서 뒤에 Handler를 붙여서 네이밍을 하고 있습니다.

///form
....
  const onSubmitHandler = async (email: VerifyEmailType) => {
  ....
  };
return(
  <form
      onSubmit={onSubmitHandler}
    />
)

코드가 길어졌다고 해서 나쁜 코드라고 할 수 있는가??

 코드가 짧아지고 역할을 확실하게 한다면 좋아 보일 수 있습니다. 그렇지만 꼭 좋은 코드라고 불리기 어려울 수 있습니다. 코드 라인 수가 짧다면 좋은 지표로 유지보수하기 좋을 수 있지만 이 점만으로는 좋은 코드라고 판단하기는 어려운 셈입니다. 제가 생각할 때 좋은 코드는 길더라도 유지보수성, 재사용성 그리고 확장성에 유리한 측면이 있는가 입니다. 이러한 코드들은 응집력이 높고 코드의 역할을 알아보기 쉬워 협업에 유리하다고 생각합니다. 개발자는 혼자 개발하는 것이 아니라 협업을 위한 개발하는 것이라 생각하기 때문입니다.

 그럼 본격적으로 함수형 프로그래밍에서 액션과 계산을 구분해보겠습니다.



우선적으로 액션과 계산 분리하기

//세금을 계산하고 dom을 조작하는 함수
function update_tax_dom() {
	set_tax_dom(shopping_cart_total * 0.10);
}

 다음은 세금 계산 코드를 작성하고 있습니다. update_tax_dom은 dom을 조작하는 부분이고 set_tax_dom()내부에는 계산 로직이 있습니다. 위의 코드의 문제와 해결방안은 무엇일까요??

  1. 코드를 선택하고 빼냅니다.
  2. 암묵적 입력과 출력을 찾습니다.
  3. 입력은 인자로 바꾸고 출력은 리턴값으로 바꿉니다.

 위의 방법으로 계산을 추출하여 표현할 수 있습니다. 위의 코드에서 가장 큰 문제는 부수적인 즉 암묵적 입력이 들어와 있습니다. shopping_cart_total은 자세히 나오지는 않았지만 전역 변수라고 볼 수 있겠습니다. update_tax_dom에서 인자로 받지도 않고 그냥 그대로 사용하였고 또한 return으로 반환하는 값 조차 표현되지 않았습니다. 이는 명시적이지 않습니다. 이 코드를 좀 더 명확하게 바꿔보겠습니다.

// dom을 업데이트 하는 함수
function update_tax_dom(){
	set_tax_dom(calc_tax(shopping_cart_total))
}

// 세금을 계산하는 함수(amount를 통해 암묵적인 전역변수 대신 명시값을 받음)
function calc_tax(amount){
	return amount * 0.01;
}

 세금을 계산하는 calc_tax를 만들어 빼내었고 amount로 계산하고자 하는 인자를 받아 return값으로 넘겨 받아 dom조작을 하고 있습니다. 그리하여 좀 더 명확하고 재사용가능한 함수가 완성되었습니다.



👍올바른 피드백은 언제든지 환영입니다~!

profile
www.mincho130.xyz <-- 블로그 이사했습니당

0개의 댓글