자바스크립트는 객체지향 프로그래밍과 함수형 프로그래밍을 지원하는 멀티 패러다임 언어입니다. 이로 인해 prototype
, class
를 통한 객체지향의 코드가 만들어지기도 하며, encodeURIComponent
, Math.max
같이 함수형 프로그래밍의 코드가 만들어지기도 합니다. 이 두가지 모두 현재까지 사용되는 패러다임이며, 실제로 두가지를 혼용해가며 사용할 때도 있습니다. 그렇기 때문에 코드를 보다보면 어떤게 함수형이고, 어떤게 객체지향인지 혼동될 때도 있으니 이 두가지를 잘 알아두어야 합니다. 이번 글에서는 많이 알려진 객체지향 보다는 다소 생소한 함수형 프로그래밍을 정리해보려합니다.
함수형 프로그래밍은 선언형 프로그래밍의 한 갈래입니다. 따라서 상태를 바꾸는 형태인 명령형과는 다르게 식과 선언으로 이루어진 선언형의 특징을 띄고 있습니다. 그리고 함수형은 다음과 같은 특징이 더 있습니다.
1급 객체(First-class citizens)라는 말을 처음 들어 보실 겁니다. 변수에 저장하고, 함수의 매개 변수나 반환 값으로서 사용할 수 있는 Entity를 이야기 합니다.
어려운 말일지 모르겠지만, 여러분이 자주 사용하던 Array.prototype.map
, Array.prototype.sort
처럼 매개 변수로 함수를 받고, React의 useCallback
처럼 함수를 반환하고, 변수에 저장하는 것을 의미합니다.
기본적으로 함수는 입력받은 값을 통해 기능을 수행한 후, 결과를 반환하는 것을 이야기합니다. 이러한 단일 목적을 가지는 함수를 “순수 함수”라고 부릅니다. 그러나 주된 목적이 존재하나, 별도의 다른 목적을 가지는 함수 또한 만들어 질 수 있습니다. 다른 목적을 나타내는 것을 “부수 효과(Side Effect)”라고 부릅니다. 간단하게 이야기하면, “함수를 동작했는데 왜 다른게 바뀌는 거지?”를 프로그래밍 용어로 표현한 겁니다. 이런 부수 효과를 가지고 있는 함수를 “불순 함수”라고도 합니다.
위 예제에서는 increase
라는 함수는 “주어진 값 만큼 증가한다”라는 주된 목적을 가집니다. 하지만, 주어진 매개 변수 이외의 value
라는 외부 상태를 통해 값을 다루고 있어, “주어진 값 만큼 증가한다” 라는 목적 외의 “외부 상태의 value
를 저장한다”라는 별도의 목적을 가지고 있습니다. 이 때문에 부수 효과를 가진 함수로서 이 함수는 불순 함수로 정의 할 수 있습니다. 이 문제를 순수 함수로 재작성 하면 다음과 같습니다.
앞서 말한 “주어진 값 만큼 증가한다”에 집중된 함수의 순수한 기능입니다. 기존의 value
라는 외부 상태를 base
라는 매개 변수로 바꾸면서, “외부 상태에 저장한다”라는 목적을 제거해 단일 목적으로 함수를 재작성 했습니다. 이로써 increase
는 순수 함수가 되었습니다.
이 처럼 외부 상태에 의존해 사용하는 함수는 여러분이 사용하는 자바스크립트에도 많이 존재합니다. 그 중에서도 Array.prototype.push
, Array.prototype.sort
와 같이 배열 값 자체를 바꾸려는 함수(사실 이 두개의 함수는 프로토타입 객체지향입니다)가 존재하며, fetch
, window.matchMedia
, document.getElementById
같이 네트워크나 브라우저 DOM이라는 외부 상태를 이용한 함수들이 존재합니다. 이러한 함수들 때문에 자바스크립트에서는 100% 완벽한 함수형 프로그래밍을 하지 못한다는 것을 아셔야합니다.
순수 함수는 부수 효과가 존재하지 않기 때문에 스레드 안정성을 보장할 수 있습니다. 또한, 테스트 케이스 작성에 더 용이하다는 장점이 있습니다.
함수형 프로그래밍에서 변수는 바뀌면 안됩니다. 객체의 속성과 배열의 요소까지도요. 값을 변경하는 건 상태를 다루는 것이고, 당연히도 순수 함수를 다루는 함수형 프로그래밍에서는 나타나선 안되는 패턴이기도 합니다. 그리고 상태를 바꾸는건 당연히 선언형 프로그래밍이 아닌 명령형 프로그래밍을 의미하게 됩니다. 이 때문에 변수 선언 방식이 가변의 let
보다는 불변 선언인 const
선언을 주로 사용하고, for
, while
, continue
같이 흐름 제어 보다는 Array.prototype.map
, Array.prototype.forEach
같은 함수형태의 흐름제어를 주로 사용하게 됩니다.
자바스크립트 진영에서 개발을 해오면서 어렴풋이 사용하던 함수형 프로그래밍을 정리했습니다. 현재도 자바스크립트는 계속 객체지향과 함수형을 병행하며 사용되고, 이로인해 코드의 규칙을 잡기 어려울 때가 있습니다. 이번 정리를 통해 좀더 함수형 프로그래밍을 개발할 때는 제대로된 규칙을 갖고 개발했으면 좋겠습니다.