Why Functional JavaScript?

wookhyung·2022년 10월 11일
0

톺아보기

목록 보기
5/8

발표 스터디 4주차 주제로 선정한, 함수형 프로그래밍에 대한 정리 글입니다.

Intro

최근 들어, 함수형 프로그래밍 이라는 키워드가 자주 보입니다. 객체지향 프로그래밍에 대해서는 이전에 몇 번 들어보기도 했고, 잘 알려진 개념이지만 함수형 프로그래밍은 조금 생소합니다. 모 기업에서 진행 했던 기술 면접에서 자바스크립트는 왜 함수형 프로그래밍 언어라고 불릴까요? 라는 질문을 받았습니다. 또한, 인프런 채용 공고에서는 우대 사항에 함수형 프로그래밍에 대한 기본적인 이해가 있으신 분이라고 명시되어 있기도 합니다.

왜 자바스크립트 개발자들에게서 함수형 프로그래밍 이라는 키워드가 계속해서 나올까요? 이번 포스팅에서는 이러한 궁금증들을 해결하기 위해, 자바스크립트의 함수형 프로그래밍에 대해서 정리해보고자 합니다.

JavaScript로 함수형 프로그래밍 배우기 - Anjana Vakil - JSUnconf


⚙️ 함수형 프로그래밍이란 무엇일까요?

함수형 프로그래밍이란, 하나의 프로그래밍 패러다임이자 코딩 스타일이며, 일종의 사고방식입니다.

함수형 프로그래밍은 여러가지 패러다임 중 하나로, 다른 예로는 명령형 프로그래밍이나 객체지향 프로그래밍이 있습니다. 프로그래밍 패러다임마다 중요하게 여기는 요소가 있고, 함수형 프로그래밍에서는 당연하게도 함수를 가장 중요하게 여깁니다.

또한, 함수형 프로그래밍은 코딩 스타일입니다. 코드를 정리하고 작성하는 스타일이며, 프로젝트에 접근하는 방식으로 일종의 사고방식이라고도 볼 수 있습니다. 문제에 대해 고민하고, 문제를 어떻게 해결할지 고민하는 방식입니다.

// ❌ Not Functional

var name = "John";
var greeting = "Hi, I'm ";
console.log(greeting + name);
// Hi, I'm John

다음 예제는 일종의 명령형 프로그래밍입니다. 변수 name에다가 "John" 을 할당하고, greeting에다가 "Hi, I'm " 을 할당하고, 출력을 하고.. 정해진 순서대로 실행되며, 함수가 존재하지 않습니다.

// ✅ Functional

function greet(name) {
  return "Hi, I'm " + name;
}
greet("John");
// Hi, I'm John

같은 상황을 함수형으로 변환 해봤습니다. greet 함수는 name을 매개변수로 받으며, name을 포함한 문자열을 반환합니다. name을 인풋으로 받아서, "Hi, I'm John"을 아웃풋으로 반환하는 코드입니다.

함수형 프로그래밍은 큰 틀에서 선언적 프로그래밍 패러다임에 속합니다. 명령형 프로그래밍은 무엇을 어떻게(How) 할 것인가에 가깝고, 선언형 프로그래밍은 무엇을(What) 할 것인가에 가깝습니다.


🤷‍♂️ 왜 자바스크립트로 함수형 프로그래밍을 할까요?

많은 개발자들은 자바스크립트로 객체지향 개발을 하면서 prototype이나, this 같은 개념에서 혼동을 겪습니다. 객체지향에 비해서 함수형 개발은 더 안전하면서 작성하기 쉬우며 디버깅과 유지보수에 용이합니다.

또한, 자바스크립트는 함수형 프로그래밍에 필요한 몇 가지 중요한 기능들을 가지고 있습니다.

간단한 예시와 함께 살펴보고, 더 자세한 내용은 아래에서 다루겠습니다.

1. first-class 함수

자바스크립트에서는 함수를 변수에 담거나, 함수를 매개변수로 넘기거나, 함수에서 함수를 반환할 수 있습니다. 이는 고차 함수(higher-order function)을 허용하여 부분 적용(partial application), currying 및 합성을 가능하게 합니다.

const add = (a, b) => a + b;

console.log(add(1, 2)); // 2
const func1 = () = () => 30;

const func2 = func1();
console.log(func2()); // 30

2. Closure

클로저는 이전 실행 컨텍스트 포스팅 에서도 다뤘습니다. 자바스크립트의 모든 함수는 클로저 함수이며, 함수가 다른 함수 내부에서 정의됐을 때 외부 함수가 종료 된 이후에도 Outer Environment Reference를 통해 외부 함수의 변수에 접근할 수 있습니다.

function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  innerFunc();
}

outerFunc(); // 10

3. 익명 함수와 간결한 람다 구문

x => x * 2, 자바스크립트는 이와 같이 간결하게 익명 함수를 만들 수 있습니다. 이는 고차원 함수로 더 작업하게 쉽게 만들어줍니다.


함수형 프로그래밍의 특징에 대해 더 자세하게 알아보겠습니다.

🛠 부작용(side-effect)과 순수 함수(Pure finction)

함수형 프로그래밍의 특징 중 하나는 부작용을 피하기 위해 순수 함수만을 사용한다는 것입니다.

부작용이란, 함수가 주어진 인풋에서 아웃풋을 계산하여 반환하지 않는 상황을 의미합니다.

예를 들자면, console.log를 통해서 무언가를 출력하는 것은 아웃풋을 반환하는 일이 아닙니다. 또한 함수 내부에서 전역 변수를 사용하여 아웃풋을 반환한다면, 인풋에 의존하지 않는 함수이기 때문에 그 함수는 순수 함수가 아닙니다. 함수 외부에 있는 전역 변수가 함수의 결과에 영향을 끼칠 수 있기 때문입니다.

정리해보면, 순수 함수는 인풋 만을 이용하여 아웃풋을 계산하여 반환해야 됩니다.

// ❌ Not Pure

var name = "John";
function greet() {
  console.log("Hi, I'm " + name);
}

여기서, greet라는 함수는 순수 함수라고 말할 수 있을까요? 없습니다.

전역 변수인 name을 받아서 출력을 하고 있기 때문에 순수하지 않습니다. 또한, greet 함수 내부에서는 아무 것도 반환하지 않고 있기 때문에 순수하지 않습니다. greet 함수가 순수 함수가 되기 위해서는 함수 내부에서 인풋을 받아, 어떤 계산 과정을 거쳐서 아웃풋을 반환하길 원하지만 여기서는 console.log 라는 다른 함수를 호출할 뿐입니다.

// ✅ Pure

function greet(name) {
  return "Hi, I'm " + name;
}

순수 함수는 이렇게 생겼습니다. 함수의 아웃풋에 영향을 끼치는 건 인풋인 name 밖에 없습니다.

🛠 고차 함수 (Higher-order function)

함수형 프로그래밍의 다른 특징으로는 고차 함수 가 있습니다. 고차 함수는 다른 함수를 인풋으로 받거나, 함수를 아웃풋으로 반환하는 함수입니다. 함수를 일종의 객체처럼 취급하여 함수 내에 함수가 있는 구조를 만들 수 있습니다.

// Higher-order function
function makeAdjectifier(adjective) {
  return function (string) {
    return adjective + " " + string;
  };
}

var coolifier = makeAdjectfier("cool");
coolifier("conference");
// cool conference

makeAdjectifier 함수가 있습니다. adjective를 인풋으로 받으며 문자열이나 숫자가 아닌 함수를 반환합니다. 반환하는 함수에서는 넘겨준 adjective에 주어진 문자열을 붙여줍니다.

makeAdjectfier 함수에 cool 이라는 문자열을 넘기고 coolifier 라는 함수를 만들었습니다. 이제 coolifier 라는 함수에 conference 라는 문자열을 넘겨주면 cool conference라는 문자열이 반환됩니다.

🛠 Don't Iterate (use map, reduce, filter... )

// ❌ statements 
const nums = [1, 2, 3, 4, 5];

function multiply(numbers, multiplier) {
  for (let i = 0; i < numbers.length; i++) {
    numbers[i] = numbers[i] * multiplier;
  }
}
// ✅ expressions
function multiply(numbers, multiplier) {
  return numbers.map(num => num * multiplier);
}

for이나 while같은 반복문 대신 map, reduce, filter 등의 내장함수를 사용하는 것이 좋습니다. map, reduce, filter 같은 함수들을 위에서 말한 고차함수라고 부릅니다. 인자로 함수를 넘겨주고 결과물을 반환받을 수 있습니다.

🛠 Avoid mutability (use immutable data)

함수형 프로그래밍에서는 데이터의 변화를 피하는 것이 좋습니다. 여기서 변화란, 객체의 위치 변경을 의미합니다.

// ❌ mutation
var rooms = ['H1','H2','H3'];
rooms[2] = 'H4';
console.log(rooms);
// ['h1','h2','h4']

객체 지향적인 관점에서 이렇게 객체를 직접 수정하는 것은 굉장히 지양합니다. 객체 안에 있는 데이터가 변경 될 때, 객체의 주소는 변하지 않지만 객체 안에 있는 데이터들의 주소가 변경됩니다. 개발자들은 객체의 주소를 가지고 핸들링하기 때문에 변화를 알기 쉽지 않습니다. 이러한 이유로 함수형 프로그래밍에서도 이러한 패턴은 지양해야 합니다.

만약, 다른 코드에서 rooms라는 변수를 사용하고 있고 rooms가 변화됐다는 걸 알지 못했다면 의도치 않은 결과를 불러 올 수 있습니다.

// ✅ No mutation
var rooms = ['H1', 'H2', 'H3'];
var newRooms = rooms.map((room) => {
  if (room === 'H3') {
    return 'H4';
  } else {
    return room;
  }
});


newRooms; => ['H1','H2','H4']
rooms; =>  ['H1','H2','H3']

모든 데이터를 불변 데이터로 취급하면 어떨까요? rooms 배열에 직접 접근하여 변경해서 사용하기 보다는, 새로운 배열을 만들어서 map 함수를 통해 newRooms라는 새로운 배열을 만들었습니다. 즉, rooms를 불변 데이터로 취급해서 변경하지 않으면서 새로운 배열을 만들어 사용하는 것입니다.

이렇게 하면, 원본 배열이 수정되지 않았기 때문에 의도치 않은 에러를 방지할 수 있습니다.

🛠 Persistent data structures for efficient immutability

...


🧐 Outro

지금까지 함수형 프로그래밍을 왜 사용하는지, 함수형 프로그래밍은 어떤 특징을 가지고 있는지에 대해 정리해봤습니다. 자바스크립트는 멀티 패러다임 언어로서, 함수형 프로그래밍에 필요한 first class 함수, 간결한 람다 구문, 클로저 등의 특징을 가지고 있습니다. 하지만, 태생이 함수형 프로그래밍 언어는 아니기에 다른 언어에는 있는 순수, 불변성, 재귀 등의 특징이 없기도 합니다.

그럼에도 React, Redux 및 Loadsh등 자바스크립트 생태계의 주요 라이브러리 및 프레임워크들은 함수형 프로그래밍의 영향을 받았고 자바스크립트는 함수형 프로그래밍 언어로써 충분하다는 평가를 받고 있습니다. 앞으로 함수형 프로그래밍은 자바스크립트 생태계에서 중요한 키워드가 될 가능성이 높으며 실제로 적용해봤을 때 어떤 점이 좋았는지 판단하기 위해 프로젝트에 적용해보며 학습할 예정입니다.

Reference

JavaScript로 함수형 프로그래밍 배우기 - Anjana Vakil - JSUnconf ⭐️⭐️⭐️
https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming 👍
함수형프로그래밍이 대세다?! (함수형 vs 객체지향)
https://boxfoxs.tistory.com/430
https://velog.io/@kyusung/함수형-프로그래밍-요약
https://devhue.github.io/blog/functional-programming
http://ruaa.me/why-functional-matters/

profile
Front-end Developer

0개의 댓글