logo

함수형 프로그래밍

함수형 프로그래밍은 무엇인가

javascript, fp


시작

소프트웨어 개발을 한다면 객체지향 프로그래밍이라던지 함수형 프로그래밍이라는 프로그래밍 패러다임을 자주 접할 수 있을 것이다. 그중 함수형 프로그래밍은 몇 년 전부터 화제가 되어왔고 특히 자바스크립트 세계에서는 너무도 쉽게 접할 수 있는 단어가 되어 버렸다. 그렇다면 함수형 프로그래밍은 무엇인가?

간단히 정의하자면 함수형 프로그래밍은 명령형이 아닌 선언형이며 순수 함수(pure function)를 사용, 조합하여 소프트웨어를 구현하는 프로세스이다.

순수 함수

함수형 프로그래밍은 순수 함수로 작성되다보니 부수효과(side effect)가 없다. 여기서 순수 함수란 프로그램에 어떠한 변화를 일으키지 않으며 같은 입력이면 같은 출력만이 존재하는 함수 형태로 결과를 예측 가능 할 수 있어서 테스트 실행에도 큰 이점을 가져다준다.

// 외부 변수가 함수 결과값에 영향
let a = 10;

function f1(b) {
  return a + b;
}

f1(10); // 20
a = 20;
f1(10); // 30

// 오직 인자만이 함수 결과값에 영향
// 순수 함수
function f2(a, b) {
  return a + b
}

f2(10, 10); // 20
f2(20, 10); // 30

불변성

함수형 프로그래밍에서는 불변성은 반드시 지켜져야 할 규칙 중 하나이다. 만약 데이터의 불변성이 지켜지지 않는다면 함수를 실행할 때 마다 입력되는 원본 데이터는 수정되거나 손실될 것이며 그로인해 버그들이 소프트웨어를 망쳐 놓게 될 것이다.

// 가변
function mutable(array) {
  array[0] = '0';
}

const props1 = ['1', '2', '3'];
mutable(props1);

// 불변
function immutable(array) {
  const mod = ['0', ...array]
  return mod;
}

const props2 = ['a', 'b', 'c']
const modifiedArray = immutable(props2);

자바스크립트에서는 const와는 구별해야된다. const는 한번 생성을 하면 재할당을 못 하지만 참조하는 객체의 속성은 변경할 수 있다. 그 외 손쉬운 불변성 관리로는 immer.js를 추천한다.

선언형

함수형 프로그래밍은 선언형으로 명령형의 어떤 방법으로 해야하는지(How)와는 달리 무엇을 하는지 (What)에 초점을 맞춘다. 오직 프로그램의 논리에 집중하며 목표를 명시하고 알고리즘을 명시하지 않는 것이다.

// 명령형
const map1 = numbers => {
  const arr = [];
  for (let i = 0; i < numbers.length; i++) {
    arr.push(numbers[i] + 10);
  }
  return arr;
};
map1([1, 2]);  // [11, 12]

// 선언형
const map2 = numbers => numbers.map(n => n  + 10);
map2([1, 2]);  // [11, 12]

명령형의 경우에는 for, if, switch, throw와 같은 구문(statement)을 더 사용하고 선언형은 값, 변수, 연산자 조합과 같은 표현식(expression)을 더 사용한다.

고차 함수

함수를 인자로 받거나 반환함으로써 동작하는 함수를 고차 함수(higher-order function)라 말한다. 함수가 주가 되는 함수형 프로그래밍에서는 함수들의 조합이나 결합이 필요한 경우가 자주 있는데 그럴 경우에 사용된다.

자바스크립트에서는 map(), filter(), reduce()가 대표적인 고차 함수이다.

// map
const numbers1 = [1, 2, 3];
const map = numbers1.map(num => num + 10) // [11, 12, 13]

// filter
const numbers2 = [10, 20, 30];
const filter = numbers2.filter(num => num > 10) // [20, 30]

// reduce
const numbers3 = [5, 10, 15];
const reduce = numbers3.reduce((accumulator, num) => accumulator + num) // 30

마치며

함수형 프로그래밍은 1930년대에 근간을 이뤘고 동시성 작업이 쉽고 안전하다는 이유로 최근에 와서 많이 주목받고 또 사용되고 있다. 비단 이런 이유말고도 코드를 간결하게 하여 가독성을 높이고 테스트의 간편함등으로 장점이 많은 프로그래밍 패러다임이다.

그렇다고 해서 모든 코드를 다 함수형 프로그래밍으로 작성해야 된다는 것은 아니다. 함수형 프로그래밍이라고 한들 모든 상황에서 정답은 아니다. 아무리 좋다한들 상황에 맞지 않으면 가장 적합한 방법을 찾는게 현명한 행동이 아닐까? 그래도 한 가지 확실한 것은 함수형 프로그래밍을 통한 사고가 항상하던 개발의 시점을 새로운 관점에서 일깨워준다는 점이다.

참고 자료