본문으로 건너뛰기

1장 함수형 길들이기

이 장의 내용
  • 함수형 사고방식
  • 함수형 프로그래밍의 정의와 필요성
  • 불변성, 순수함수 원리
  • 함수형 프로그래밍 기법 및 그것이 설계 전반에 미치는 영향
마이클 페더스, 트위터에 쓴 글에서
"겍체 지향(OO)은 가동부를 캡슐화하여 코드의 이해를 돕는다.
함수형 프로그래밍(FP)은 가동부를 최소화하여 코드의 이해를 돕는다."

개발자의 본능은 확작성 좋고 깔끔한 애플리케이션 아키텍처를 구축하는 데 유용한 프레임워크에 크게 끌리지만, 현행 코드베이스는 이미 너무 복잡해진 상태라서 기본 설계 원리부터 다시 검토해야 하는 어려움이 있습니다.

어떤 문제는 객체지향 설계방식으로도 해결할 수 있지만, 자바스크립트는 상태 공유가 보편적인, 참으로 동적인 언어라서 조금만 시간이 지나도 복잡해지면서 가독성이 떨어지고 관리하기 어려운 코드가 되기 일쑤입니다. 객체지향 설계 방향이 잘못된 건 아니지만 현실의 문제를 해결하기엔 역부족이죠. 최근 유행하기 시작한 리액티브 프로그래밍은 데이터 흐름과 변경 전파에 초점을 둡니다. 여러분이 반드시 자문해봐야 할 애플리케이션의 설계 요소를 정리해보겠습니다.

  • 확장성: 추가 기능을 지원하기 위해 계속 코드를 리팩터링해야 하는가?
  • 모듈화 용이성: 파일 하나를 고치면 다른 파일도 영향을 받는가?
  • 재사용성: 중복이 많은가?
  • 테스트성: 함수를 단위 테스트하기 어려운가?
  • 헤아리기 쉬움: 체계도 없고 따라가기 어려운 코드인가?

1장은 함수형 프로그래밍이 무엇인지 살펴보고, 함수형 패러다임이 왜 중요하면서도 유용한지 설명합니다. 불변성(immutability), 순수함수(pure function)의 핵심 원리를 소개하고, 그다음 다양한 FP 기법과 이런 기법이 프로그램 설계 방식에 어떤 영향을 주는지 알아봅니다.

1.1 함수형 프로그래밍은 과연 유용한가?

자바스크립트 맥락에서 보면, FP 사고방식은 자바스크립트만의 매우 표현적인 특성을 가다듬어, 깔끔하면서도 모듈적인, 테스트하기 좋고 간결한 코드를 작성하는 데 도움이 됩니다.

FP로 코드를 작성하면 순수함수에 기반을 두고 이미 검증된 기법과 관례에 따라 구현하면 코드가 점점 복잡해지더라도 헤아리기 쉬운 방향으로 작성할 수 있습니다. 전체 애플리케이션 품질을 향상시키는 동시에 자바스크립트 언어를 더 잘 이해하게 됩니다.

1.2 함수형 프로그래밍이란?

함수형 프로그래밍이란, 한마디로 함수 사용을 강조하는 소프트웨어 개발 스타일입니다. 목표는 애플리케이션의 부수효과(side effect)를 방지하고 상태 변이(mutation of state)를 감소하기 위해 **데이터의 제어 흐름과 연산을 추상(abstract)**하는 것입니다.

HTML 페이지에 텍스트를 보여주는 간단한 자바스크립트 프로그램으로 예시를 들어보겠습니다.

function printMessage(elementId, format, message) {
document.querySelector(
`#${elementId}`
).innerHTML = `<${format}>${message}</${format}>`;
}

printMessage("msg", "h1", "Hello World");

함수이지만 완벽히 재사용 가능한 코드는 아닙니다. 메시지를 HTML 페이지 대신 파일에 쓴다면 어떨까요? 매개변수가 단순한 스칼라 값이 아닌, 특정 기능을 함수에 추가하여 매개변수로 전달하는, 다시 말해 함수를 매개변수화하는 전혀 다른 차원의 과정을 떠올려야 합니다. 함수형 프로그램은 함수를 아주 왕성하게 활용합니다. 여러 함수를 서로 합성하고 평가해서 더 많은 기능을 탑재하는 것이 유일한 목표니까요.

[코드 1-1] 함수형 printMessage
var printMessage = run(addToDom("msg"), h1, echo);

printMessage("Hello World");

일단 h1은 스칼라 값이 아닌, addToDom, echo와 같은 함수입니다. 작은 함수들을 재료로 새로운 함수를 만들어내는 것처럼 보이네요.

[코드 1-1]은 재사용성과 믿음성(reliability)이 좋고 이해하기 쉬운, 더 작은 조각들로 프로그램을 나눈 후, 전체적으로 더 헤아리기 쉬운 형태의 프로그램으로 다시 조합하는 과정을 나타냅니다.

함수형 코드는 왜 이런 모습일까요? 기본적으로, 마치 알고리즘의 초기 조건을 조정하듯, 본연의 기능은 그대로 간직한 채 코드를 쉽게 변경하기 위해 코드 자체를 매개변수화하는 것입니다. 이렇게 하면 내부 로직은 하나도 안 고치고도 예를 들어 printMessage가 메시지를 2회 표시하게, 헤더는 h2 요소로, DOM 대신 콘솔에 출력하게 변경하는 일도 수월해집니다.

[코드 1-2] printMessage를 확장
var printMessage = run(console.log, repeat(2), h2, echo);

printMessage("Get Functional");

함수형 프로그래밍을 온전히 이해하려면, 먼저 그 이면에 깔려 있는 다음 기본 개념을 숙지해야 합니다.

  • 선언적 프로그래밍
  • 순수함수
  • 참조 투명성
  • 불변성

1.2.1 함수형 프로그래밍은 선언적

함수형 프로그래밍은 큰 틀에서 선언적 프로그래밍 패러다임에 속합니다. 내부적으로 코드를 어떻게 구현했는지, 데이터는 어떻게 흘러가는지 밝히지 않은 채 연산/작업을 표현하는 사상이지요. 명령형 프로그램은 어떤 결과를 내기 위해 시스템의 상태를 변경하는 구문을 위에서 아래로 쭉 늘어놓은 순차열에 불과합니다.

명령형 코드
var array = [0, 1, 2, 3, 4];
for (let i = 0; i < array.length; i++) {
array[i] = Math.pow(array[i], 2);
}
array; // -> [0, 1, 4, 9, 16]

명령형 프로그래밍은 컴퓨터에게 원하는 작업을 어떻게 하는지 상세히 이릅니다.

이와 달리 선언적 프로그래밍은 프로그램의 서술부와 평가부를 분리하여, 제어흐름이나 상태 변화를 특정하지 않고도 프로그램 로직이 무엇인지를 표현식으로 나타냅니다. SQL 구문도 선언적 프로그래밍의 한 예입니다. SQL 쿼리를 보면, 데이터를 실제로 가져오는 내부 메커니즘은 추상한 상태에서 그 결과가 어떻게 나와야 하는지를 구문으로 서술합니다.

같은 작업이라도 함수형으로 접근하면, 개발자가 각 요소를 올바르게 작동시키는 일에만 전념하고 루프 제어는 시스템의 다른 파트에 일임할 수 있습니다. 다음과 같이 힘든 일은 Array.map()에게 모두 맡기면 그만이지요.

선언적 코드
[0, 1, 2, 3, 4].map(function (num) {
return Math.pow(num, 2);
});

코드가 길어지면 버그가 날 가능성도 높아지고, 일반 루프는 함수로 추상하지 않는 한 재사용 자체가 안됩니다. 지금부터 우리가 할 일이 바로 함수로 추상하는 작업입니다. 함수를 매개변수로 받는 map, reduce, filter 같은 일급 고계함수(higher-order function)을 이용해 재사용성, 확장성이 우수한 선언적 코드로 대체합니다.

루프를 함수로 추상하면 ES6부터 새로 선보인 람다 표현식이나 화살표 함수를 쓸 수 있습니다. 람다 표현식은 함수 인수로 전달 가능한 익명 함수를 대체할 수 있는 깔끔한 수단입니다. 코드도 덜 쓰면서 말이죠.

람다 표현식
[0, 1, 2, 3, 4].map((num) => Math.pow(num, 2));
람다 표기를 일반 함수 표기로 전환

람다 표현식은 함수 호출의 구조를 가장 중요한 부분만 남기고 축약하므로 일반 함수 표기보다 구문상 이점이 많습니다.

왜 루프를 제거해야 할까요? 루프는 재사용하기도 어렵거니와 다른 연산에 끼워 넣기도 어려운 명령형 제어 구조물입니다. 또 루프는 성격상 반복할 때마다 값이나 상태가 계속 바뀝니다. 그러나 함수형 프로그램은 무상태성불변성을 지향합니다. 무상태 코드는 전역 상태를 바꾸거나 혼선을 일으킬 가능성이 단 1%도 없습니다. 상태를 두지 않으려면 부수효과와 상태 변이를 일으키지 않는 순수함수를 써야 합니다.

1.2.2 순수함수와 부수효과

함수형 프로그래밍은 순수함수로 구성된 불변 프로그램 구축을 전제로 합니다. 순수함수의 특성은 다음과 같습니다.

  • 주어진 입력에만 의존할 뿐, 평가 도중 또는 호출 간 변경될 수 있는 숨겨진 값이나 외부 상태와 무관하게 작성합니다.
  • 전역 객체나 레퍼런스로 전달된 매개변수를 수정하는 등 함수 스코프 밖에서 어떠한 변경도 일으키지 않습니다.

일반적으로 외부 자원을 상태로 데이터를 읽고 쓰는 함수는 부수효과를 동반합니다. Date.now()처럼 많이 쓰이는 날짜/시간 함수도 미리 헤아릴 수 있는 결괏값을 내지 않기 때문에 순수함수가 아닙니다. this 키워드를 거쳐 인스턴스 데이터에 접근하는 것 역시 부수효과가 유발되는 흔한 예입니다. 부수효과가 발생하는 상황은 다양합니다.

  • 전역 범위에서 변수, 속성, 자료구조를 변경
  • 함수의 원래 인수 값을 변경
  • 사용자 입력을 처리
  • 예외를 일으킨 해당 함수가 붙잡지 않고 그대로 예외를 던짐
  • 화면 또는 로그 파일에 출력
  • HTML 문서, 브라우저 쿠키, DB에 질의

객체를 생성/변경하지 못하고 콘솔에 출력조차 할 수 없다면 그런 프로그램이 대체 무슨 소용일까요? 역동적으로 움직이며 온갖 변경이 난무하는 프로그램에서 순수함수를 사용하기란 현실적으로 어려울 수 있지만, 실제로 함수형 프로그래밍은 모든 상태 변이를 근절하자는 건 아니고, 상태 변이를 줄이고 관리할 수 있는 프레임워크를 제공하여 순수/불순 함수를 구분하자는 겁니다. 불순한 코드는 방금 전에도 예시했듯이 밖에서 가시적인 부수효과를 일으키죠.

[코드 1-3] 부수효과를 일으키는 명령형 showStudent 함수
function showStudent(ssn) {
let student = db.find(ssn);
if (student !== null) {
document.querySelector(`#${elementId}`).innerHTML = `${student.ssn},
${student.firstname},
${student.lastname}`;
} else {
throw new Error("학생을 찾을 수 없습니다!");
}
}

showStudent("444-44-4444");

이 함수는 몇 가지 부수효과를 일으킵니다.

  • 변수 db를 통해 데이터에 접근하는데 함수 서명에는 이런 매개변수가 없으니 이는 외부 변수입니다.
  • elementId는 그 값이 언제라도 바뀔 수 있는 전역 변수입니다.
  • HTML 요소를 직접 고칩니다. HTML 문서는 전역 공유자원입니다.
  • 학생 레코드를 찾지 못해 예외를 던지면 전체 프로그램의 스택이 풀리면서 종료될 것입니다.

[코드 1-3]의 함수는 외부 자원에 의존하므로 코드가 유연하지 않고 다루기가 힘들뿐더러 테스트 역시 어렵습니다. 반면, 순수함수는 서명에 정규 매개변수를 빠짐없이 명시하므로 코드를 이해하고 사용하기 쉽습니다.

두 가지를 개선해보겠습니다.

  • 긴 함수를 하나의 목적을 가진 짧은 함수로 각각 분리한다.
  • 함수가 해야 할 작업에 필요한 인수를 모두 명시하여 부수효과 개수를 줄인다.

먼저, 학생 레코드를 조회하는 일과 이를 화면에 그리는 일을 분리합니다. 여기서 커링이라는 유명한 FP 기법을 여러분에게 소개합니다. 커링은 함수의 여러 인수를 부분적으로 나누어 세팅하는 것입니다.

[코드 1-4] showStudent 프로그램을 분해
var find = curry((db, id) => {
let obj = db.find(id);
if (obj === null) {
throw new Error("객체를 찾을 수 없습니다!");
}
return obj;
});

var csv = (student) =>
`${student.ssn}, ${student.firstname}, ${student.lastname}`;

var append = curry((selector, info) => {
document.querySelector(selector).innerHTML = info;
});

한 가지만 개선했는데도 여러 장점이 눈에 띕니다.

  • 재사용 가능한 컴포넌트 3개로 나뉘어 코드가 훨씬 유연해졌습니다.
  • 이렇게 잘게 나뉜 함수를 재사용하면 신경 써서 관리할 코드 크기가 확 줄기 때문에 생산성을 높일 수 있습니다.
  • 프로그램이 해야 할 일들을 고수준에서 단계별로 명확하게 보여주는 선언적 스타일을 따르므로 코드 가독성이 향상됩니다.
  • 무엇보다 중요한 건, HTML 객체와의 상호작용을 자체 함수로 빼내어 순수하지 않은 로직을 순수함수에서 배제했다는 점입니다.

부수효과를 줄임으로써 외부조건 변화에 덜 취약한 프로그램이 되었습니다. 이처럼 함수가 일관된 반환값을 보장하도록 해서 전체 함수 결과를 예측 가능한 방향으로 유도하면 여러모로 이롭습니다. 이것이 바로 참조 투명성이라는 순수함수 본연의 특징입니다.

1.2.3 참조 투명성과 치환성

참조 투명성은 순수함수를 정의하는 좀 더 공식적인 방법이며, 여기서 순수성이란 함수의 인수와 결괏값 사이의 순수한 매핑 관계를 의미합니다. 따라서 어떤 함수가 동일한 입력을 받았을 때 동일한 결과를 내면 이를 참조 투명한 함수라고 합니다.

참조 투명한 함수로 만들려면 이 함수가 의존하는 상태, 즉 외부 변수를 제거하고 함수 서명에 정규 매개변수로 명시해야 합니다.

이런 함수는 코드를 테스트하기 쉽고 전체 로직을 파악하는 것도 쉽습니다.

명령형
increment();
increment();
print(counter); // -> ?
함수형
var plus2 = run(increment, increment);
print(plus2(0));

명령형 버전은 외부 변수 counter 값이 언제 어떻게 바뀔지 모르므로 반환값을 예측하기 어렵고 일관성이 없으므로 함수를 계속 호출하면 엉뚱한 결괏값이 나올 수 있습니다. 참조 투명한 함수형 버전은 항상 옳은 결과를 내며 에러 날 일이 없습니다.

이런 식으로 구축한 프로그램은 시스템의 상태를 머릿속으로 그려볼 수 있고 코드를 재작성하거나 치환하더라도 원하는 결과를 얻을 수 있기 때문에 헤아리기가 쉽습니다.

함수 인수를 전부 명확하게 정의하면 스칼라 값을 비롯해 대부분의 경우 부수효과를 예방할 수 있지만, 객체를 레퍼런스로 넘길 때 실수로 객체에 변이를 일으키지 않도록 주의해야 합니다.

1.2.4 불변 데이터 유지하기

불변 데이터는 한번 생성된 후에는 절대 바뀌지 않습니다.

함수형 프로그래밍은, 외부에서 관찰 가능한 부수효과가 제거된 불변 프로그램을 작성하기 위해 순수함수를 선언적으로 평가하는 것입니다.

오늘날 자바스크립트 개발자가 직면한 문제의 원인은, 대부분 뚜렷한 체계 없이 분기 처리를 남발하고 외부 공유 변수에 지나치게 의존하는 덩치 큰 함수를 과용하는 데 있습니다.

함수를 순수 연산의 관점에서 데이터를 절대 변경하지 않는 고정된 작업 단위로 바라본다면 확실히 잠재적인 버그는 줄게 될 것입니다.

1.3 함수형 프로그래밍의 좋은 점

함수형 프로그래밍의 덕을 보려면, 함수형으로 생각하며 적절한 도구를 구사할 줄 알아야 합니다. 이 절은 여러분의 함수형 인지력을 향상시키고자 핵심 기법 몇 가지를 소개합니다. 직관적으로 단순한 함수들을 조합해서 완전한 해법을 제시할 수 있게 될 겁니다.

  • 간단한 함수들로 작업을 분해한다.
  • 흐름 체인으로 데이터를 처리한다.
  • 리액티브 패러다임을 실현하여 이벤트 중심 코드의 복잡성을 줄인다.

1.3.1 복잡한 작업을 분해하도록 유도

함수형 프로그래밍은 고수준에서 보면, 사실상 분해(프로그램을 작은 조작들로 쪼갬)와 합성(작은 조각들을 다시 합침) 간의 상호작용이라 할 수 있습니다. 이러한 양면성 덕분에 함수형 프로그램은 모듈적으로, 효율적으로 동작합니다. 모듈성의 단위, 곧 작업 단위는 바로 함수 자신입니다.

FP에서 모듈화는 단일성의 원리와 밀접한 관련이 있습니다. 모름지기 함수는 저마다 한 가지 목표만 바라봐야 한다는 사상이지요. 단순 함수를 엮어 붙이려면 반드시 입력 및 출력 형식을 서로 맞춰야 하는데, 순수성과 참조 투명성이 여러분이 이런 사고방식을 가지도록 안내합니다. 참조 투명성을 설명할 때, 함수의 복잡도는 함수가 받는 인수의 개수와 직접적으로 연관되는 경우가 많다고 했습니다.

run은 이 책에서 가장 중요한 합성이라는 기법을 구현한 함수로, 두 함수를 합성하면 첫 번째 함수의 결과를 다음 함수에 밀어 넣는 새로운 함수가 탄생합니다. 두 함수 f,g의 합성 함수를 수학적으로 쓰면 다음과 같습니다.

f * g = f(g(x))

이 수식은 'f 합성 g'라고 읽습니다.

함수형으로 합성한 코드는 전체 표현식의 의미를 개별 조각의 의미에서 추론할 수 있습니다. 함수형으로 합성한 코드는 전체 표현식의 의미를 개별 조각의 의미에서 추론할 수 있습니다.

또한 함수 합성은 고수준의 추상화를 통해 자세한 내막을 밝히지 않아도 코드가 수행하는 전단계를 일목요연하게 나타냅니다. 부드럽게 흘러가는 모듈적인 코드를 작성하는 방법이 합성만 있는 건 아닙니다. 체인을 걸 듯 연산을 연결하여 연산 순차열을 만드는 방법도 있습니다.

1.3.2 데이터를 매끄럽게 체이닝하여 처리

map 이외에도 쾌적하고 강력한 함수형 라이브러리를 이용하면 어느 자바스크립트 프로젝트라도 다양한 고계함수를 마음껏 가져다 쓸 수 있습니다. 체인은 같은 객체를 반환하는 순차적인 함수 호출입니다.

복수 과목을 수강한 학생들의 평균 점수를 계산하는 명령형 코드
let enrollment = [
{ enrolled: 2, grade: 100 },
{ enrolled: 2, grade: 80 },
{ enrolled: 1, grade: 89 },
];

var totalGrades = 0;
var totalStudentsFound = 0;
for (let i = 0; i < enrollment.length; i++) {
let student = enrollment[i];
if (student !== null) {
if (student.enrolled > 1) {
totalGrades += student.grade;
totalStudentsFound++;
}
}
}
var average = totalGrades / totalStudentsFound; // -> 90

함수형 마음가짐으로 이 문제를 분해하면 대략 세 가지 단계를 거쳐야 합니다.

  • 자료 집합을 적절히 선택합니다.
  • 학생의 점수를 얻습니다.
  • 평균 점수를 계산합니다.

각 단계에 해당하는 함수를 로데시JS로 묶으면 [코드 1-5] 같은 함수 체인이 형성됩니다. 함수체인은 필요한 시점까지 실행을 미루는 **느긋한 평가(lazy evaluation)**를 수행합니ㅏ. 다른 데에선 전혀 쓸 일이 없는 일련의 코드를 전부 실행하지 않아도 되니 CPU 부하가 줄어들어 성능이 좋아지죠. 이렇게 하면 다른 함수형 언어에 기본 탑재된 **필요 시 호출(call by need)**동작을 효과적으로 모방할 수 있습니다.

[코드 1-5] 함수 체인으로 프로그래밍
_.chain(enrollment)
.filter((student) => student.enrolled > 1)
.pluck("grade")
.average()
.value(); // -> 90

명령형 프로그램에서 변수를 선언해서 그 값을 바꾸고, 루프를 반복하고, if-else 구문으로 분기했던 일들을 이제 더 이상 필요가 없다는 사실만 기억하기 바랍니다.

위 예제는 우리가 사용하는 프로그램에 삽압하기 마련인 많은 에러 처리 코드를 모두 무시하고 건너뛰었습니다. 예외를 던지는 건 부수효과를 유발한다고 했었죠. 순수 학문적인 함수형 프로그래밍에는 예외가 존재하지 않지만, 실세계에서 예외를 완전히 배제하기란 어렵습니다. 순수 에러 처리와 예외 처리는 구별해야 한느데, 어쨋든 우리의 목표는 가급적 순수 에러 처리를 하도록 구현하고, 이전 코드처럼 진짜 예외적인 상황에서는 예외가 나게끔 허용하는 것입니다.

다행히 몇몇 순수 함수형 디자인 패턴을 적용하면 풍부한 표현성을 희생하지 않고도 탄탄한 에러 처리 로직을 구사할 수 있습니다.

1.3.3 복잡한 비동기 애플리케이션에서도 신속하게 반응

콜백 패턴은 성공/실패 처리 로직이 중첩된 형태로 흩뿌려져 있기 때문에 코드의 선형 흐름이 깨지고 무슨 일을 하는지 파악하기 어렵습니다.

리액티브 프로그래밍은 함수형 프로그래밍 중에서 가장 흥미진진한 응용 분야일 겁니다. 비동기 코드, 이벤트 중심 코드의 복잡도를 현저하게 줄이는 데 큰 도움이 되지요.

리액티브 패러다임의 가장 큰 장점은, 더 높은 수준으로 코드를 추상하여 비동기, 이벤트 기반 프로그램을 설정하느라 반복되는 판박이 코드는 아예 잊고 비즈니스 로직에만 전념할 수 있게 해준다는 겁니다. 또 함수를 체인으로 묶고 합성하는 FP의 능력을 최대한 이끌어낼 수 있습니다.

[코드 1-6] 학생의 SSN을 읽고 올바른지 검증하는 명령형 프로그램
var valid = false;
var elem = document.querySelector("#student-ssn");
elem.onkeyup = function (event) {
var val = elem.value;
if (val !== null && val.length !== 0) {
val = val.replace(/^\s*|\s*$|\-s/g, "");
if (val.length === 9) {
console.log(`올바른 SSN: ${val}!`);
valid = true;
}
} else {
console.log(`잘못된 SSN: ${val}!`);
}
};

하려는 일은 단순한데 코드는 복잡해 보이고, 게다가 비즈니스 로직이 모두 한곳에 집중되어 있어 모듈성도 결여되어 있습니다. 무엇보다 이 함수는 외부 상태에 의존하는 탓에 재사용이 어렵습니다.

리액티브 패러다임은 옵저버블이라는 아주 중요한 장치를 매개로 움직입니다. 옵저버블을 이용하면 데이터 스트림을 구독해서 원하는 연산을 우아하게 합성 및 체이닝하여 어리할 수 있습니다.

학생의 SSN을 읽고 올바른지 검증하는 함수형 프로그램
Rx.Observable.fromEvent(document.querySelector("#student-ssn"), "keyup")
.pluck("srcElement", "value")
.map((ssn) => ssn.replace(/^\s*|\s*$|\-s/g, ""))
.filter((ssn) => ssn !== null && ssn.length === 9)
.subscribe((validSsn) => {
console.log(`올바른 SSN ${validSsn}!`);
});

[코드 1-7]에서 가장 주목해야 할 부분은, 수행하는 모든 연산이 완전한 불변이고 비즈니스 로직은 모두 개별 함수로 나뉘었다는 점입니다.

마이클 페더스의 말에 의하면 함수형 프로그래밍을 코드에 적용하는 건 전부를 얻거나 전부를 잃는 식의 접근 방식이 아닙니다. 이미 객체지향형 아키텍처와 FP를 범용하여 혜택을 본 애플리케이션 사례는 많습니다. FP는 불변성과 공유 상태를 엄격하게 통제하므로 멀티스레드 프로그램도 보다 직관적으로 작성할 수 있습니다.

1.4 마치며

  • 순수함수를 사용한 코드는 전역 상태를 바꾸거나 깨뜨릴 일이 전혀 없으므로 테스트, 유지보수가 더 쉬운 코드를 개발하는 데 도움이 됩니다.
  • 함수형 프로그래밍은 코드를 선언적으로 작성하므로 헤아리기 쉽고 전체 애플리케이션의 가독성 역시 향상됩니다. 또 함수와 람다 표현식을 조합하여 깔끔하게 코딩할 수 있습니다.
  • 여러 원소로 구성된 컬렉션 데이터는 map, reduce 같은 연산을 함수 체인으로 연결하여 물 흐르듯 매끄럽게 처리할 수 있습니다.
  • 함수형 프로그래밍은 함수를 기본적인 구성 요소로 취급합니다. 이는 일급/고계함수 개념에 기반을 두며 코드의 모듈성, 재사용성을 높입니다.
  • 리액티브/함수형 프로그래밍을 융합하면 이벤트 기반 프로그램 특유의 복잡성을 줄일 수 있습니다.