본문 바로가기

함수형 프로그래밍

함수형 자바스크립트 (1) - 함수형으로 사고하기

함수형 프로그래밍에 대해 학습한 내용을 정리하고자 합니다.

 

함수형 프로그래밍이란?

함수형 프로그래밍(이하 FP)이란 말 그대로 '함수'의 사용을 강조하는 프로그래밍 방식을 의미합니다. 물론 우리는 평소에도 당연히 함수를 사용하여 프로그래밍을 해왔기 때문에 새롭지 않다고 생각할 수 있습니다. 그러나 FP는 단순히 '함수를 사용하여 프로그래밍하는 것'을 의미하지 않습니다. FP는 문제를 접근하는 사고방식의 변화를 요구합니다. 그렇다면 어떤 사고 방식으로 접근해야 하는지 알아보겠습니다. 

 

함수형으로 사고하기

위키피디아 영문 페이지에 있는 함수형 프로그래밍에 대한 설명입니다. 

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions.

즉, 함수형 프로그래밍은 함수들의 합성과 적용을 통해 프로그램을 구성하는 프로그래밍 패러다임입니다. 함수형 프로그래밍에서는 함수들을 합성하고, 합성된 새로운 함수를 적용하여 문제를 해결하고자 합니다. 기존의 객체지향 프로그래밍 패러다임과는 다소 다른 방식으로 문제를 해결합니다. 그래서 처음 FP에 대해서 배우게 될때는 이러한 사고 방식의 전환이 필요합니다. 

FP의 필수 조건

위에 정의에서 알수 있듯이 FP에서는 함수의 합성이 매우 중요합니다. 따라서 함수형 프로그래밍이 가능하려면 한가지 필수 조건이 있습니다. 바로 함수가 일급시민(first-class citizens)이어야 한다는 것입니다. 함수가 일급시민이란 것은, 변수에 함수를 바인딩할 수 있으며, 매개변수, 함수의 리턴값으로 함수를 사용할 수 있음을 말합니다. 즉, 함수를 일반 데이터 타입처럼 다룰 수 있어야 한다는 겁니다. 자바스크립트에서 함수는 일급시민이기 때문에, 함수형 프로그래밍에 적합하다고 볼 수 있습니다.

함수형 프로그래밍의 기본 개념

함수형 프로그래밍을 온전히 이해하려면 그 이면에 깔려있는 기본 개념들을 알아야 합니다. 하나씩 알아보겠습니다.

 

선언적 프로그래밍

함수형 프로그래밍은 큰 틀에서 선언적 프로그래밍 패러다임에 속합니다. 선언적 프로그래밍이란, 내부적으로 어떻게 동작하는지 코드를 밝히지 않고, 작업할 것을 명시하는 방식의 프로그래밍입니다. 선언적 프로그래밍과는 다르게 절차적, 혹은 명령형 프로그래밍은 어떤 결과를 내기 위해 시스템의 상태를 변경하는 구문을 위에서 아래로 늘어놓고 순차적으로 실행합니다. 예를 들어 배열의 모든 수에 1을 더하는 코드를 짠다고 한다면 명령형 프로그래밍 방식으로는 다음처럼 짤 수 있습니다.

const arr = [1,2,3,4,5,6]

for (let i = 0; i < arr.length; i++) {
	arr[i] = arr[i] + 1
}

명령형 프로그래밍에서는 하고자하는 작업을 상세히 이릅니다. 이와 달리 선언적 프로그래밍에서는 서술부와 평가부를 분리하여, 제어 흐름이나 상태 변화를 특정하지 않고도 프로그램 로직이 무엇인지를 표현식으로 나타냅니다. 

const arr = [1,2,3,4,5,6].map(val => val + 1)

이전 코드와 비교하면 루프를 돌고, 배열을 인덱스로 일일이 접근하여 값을 변경해주는 코드를 작성할 부담을 줄일 수 있습니다. 이를 통해 버그가 날 가능성도 줄어들고, 재사용성도 높아진다는 것을 확인할 수 있습니다. 함수형 프로그래밍에서는 이처럼 수동 루프를 숨기고 함수를 매개변수 받는 map, reduce, filter 등의 일급 고계함수를 이용해 재사용성, 확장성이 우수한 선언적 코드를 작성합니다.

 

순수 함수

함수형 프로그래밍에서는 순수함수로 구성된 불변 프로그램을 구축하는 것을 목표로 합니다. 순수함수란 다음을 만족하는 함수를 의미합니다.

  • 주어진 입력에만 의존하며, 동일한 입력값에는 항상 동일한 출력값을 반환한다.
  • 부수 효과(side effect)를 발생하지 않는다.

부수효과란 함수가 함수 밖에 변수를 접근/변경 하거나, 인자의 값을 수정하거나, I/O 작업을 수행하는 것을 의미합니다.

 

예를 들어, 다음 함수는 순수함수입니다.

function add(x, y) {
  return x + y;
}

add 함수는 x와 y를 인자로 받으며 항상 동일한 결과를 리턴하며, 어떠한 부수효과들도 발생시키지 않습니다.

다음은 불순한 함수들을 보겠습니다.

// Impure: 함수 외부에 존재하는 값 참조
let one = 1

function addOne(x) {
  return x + one
}

// Impure: 인자의 속성 변경
const obj = { a: 1 }

function changeProp(x) {
  x.a = 2
}

// Impure: 동일한 값을 반환하지 않음
function getRandomValue() {
  return Math.random()
}

오직 순수함수만으로 프로그램을 작성하는 것은 현실적으로 불가능합니다. 함수형 프로그래밍이 추구하고자 하는 목표도 모든 함수를 순수하게 작성하고자 하는 것이 아니라, 순수/불순 함수를 구분하는 것입니다.

참조 투명성

어떤 표현식을 대응하는 값으로 대체하여도 프로그램의 동작이 변경되지 않는 것을 참조 투명하다고 합니다. 즉 그 표현식은 순수하며, 부수효과를 일으키지 않아야 합니다. 쉽게 말하자면 참조 투명성은 동일한 입력에 대해 동일한 출력을 내는 것을 의미하며 순수함수를 정의하는 방법입니다. 참조 투명한 함수를 만들기 위해선 외부 변수에 의존을 제거하고 사용하는 변수를 매개변수로 명시해야 합니다. 

불변성

불변성은 자료형이 변하지 않는다는 의미입니다. 자바스크립트의 모든 기본형(숫자, 문자)은 처음부터 불변입니다. 그러나 객체, 배열은 불변이 아닙니다. 우리는 배열에 새로운 값을 추가하거나, 삭제할 수 있으며, 객체에 새로운 속성을 추가, 변경 혹은 제거 할 수 있습니다. 가변적인 데이터는 함수 인자로 전달될 경우 인자의 값이 변경되어 부수효과가 발생할 수 있습니다. 따라서 우리는 데이터를 불변하게 유지하고자 노력해야 합니다.

 

함수형 프로그래밍의 장점

제가 함수형 프로그래밍을 공부하면서 느낀 장점들은 다음과 같습니다.

재사용성이 증가합니다

순수함수로 작성된 함수들은 쉽게 재사용이 가능하며 함수들을 합성하여 새로운 함수를 만들어 사용할 수 있습니다.

코드 가독성이 향상됩니다. 

순수함수로 작성된 함수들은 부수효과가 없기 때문에 함수의 역할에 대해 쉽게 알아볼 수 있습니다.

코드가 간결해집니다.

추상화를 통해 코드의 자세한 내용을 숨기고 작업하고자 하는 내용을 선언적으로 표시할 수 있습니다.

테스트 코드 작성이 용이합니다.

순수함수는 동일한 입력에 대해 동일한 결과값을 예상할 수 있으므로 테스트 코드 작성이 용이합니다.

 

함수형 프로그래밍의 단점

반대로 함수형 프로그래밍의 단점이라고 생각되는 부분입니다.

초기 학습비용이 높습니다.

객체지향 프로그래밍, 명령형 프로그래밍에 익숙한 사람이 처음으로 함수형으로 작성된 코드를 보면 이해하기가 쉽지 않습니다. 그 동안의 프로그래밍 방식과는 너무나도 다르기 때문에 사고방식의 변화가 필요합니다.

 

메모리를 많이 차치합니다.

함수형 프로그래밍이 탄생한지 오래되었음에도 불구하고 최근에서야 인기를 얻는 이유 중에 하나가 아닐까 싶습니다. 함수형 프로그래밍은 불변한 데이터를 다루기 때문에 데이터의 변경이 필요한 경우 데이터를 수정하는 것이 아니라 기존 데이터를 복제하여 새로운 데이터를 생성합니다. 이 과정에서 많은 데이터를 사용하게 됩니다. 

 

마무리

이번 글에서는 함수형 프로그래밍에 대해 간략히 알아봤습니다. 다음 글에서는 자바스크립트에서 함수형으로 프로그래밍하는 방법에 대해 알아보겠습니다.

 

정리

  • 함수형 프로그래밍은 함수의 사용을 강조하는 프로그래밍 패러다임이다.
  • 함수형 프로그래밍은 함수의 순수함수들을 합성하고 적용하며 프로그램을 구성하는 방식을 사용한다.
  • 함수형 프로그래밍은 재사용성이 높은 코드를 작성할 수 있으며, 코드 가독성이 증가하고 데스트 코드 작성이 용이하다.
  • 그러나 함수형 프로그래밍은 초기에 학습비용이 높으며, 불변 데이터의 사용으로 인해 메모리를 많이 사용한다.

 

참고 서적

[함수형 자바스크립트] : http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791162240427&orderClick=LEa&Kc=