Search
💡

함수형 프로그래밍, 왜 쓰는 걸까?

생성일
2025/05/27
URL
안녕하세요, 장동호입니다!
오늘은 함수형 프로그래밍에 대해 이야기 해보려고 합니다.

함수형 프로그래밍, 왜 쓰는 걸까?

프로그래밍에는 여러 가지 방식이 있습니다. 객체지향(OOP)과 함수형 프로그래밍(FP)은 그 중 대표적인 두 패러다임인데요, 이 둘은 충돌하는 개념이 아닙니다. 오히려 필요에 따라 적절히 조합해 사용할 수 있습니다.
오늘은 함수형 프로그래밍이 왜 등장했고, 어떤 장점을 가지는지 간단한 예제를 통해 이해해보겠습니다.

절차지향 코드 vs 함수형 코드

// 절차지향 방식 const numbers = [1, 2, 3, 4, 5, 6]; const evens = []; for (let num of numbers) { if (num % 2 === 0) { console.log("짝수:", num); evens.push(num); } } const squares = []; for (let num of evens) { const square = num ** 2; console.log("제곱:", square); squares.push(square); } let sum = 0; for (let num of squares) { sum += num; } console.log("총합:", sum);
TypeScript
복사
// 함수형 방식 const numbers = [1, 2, 3, 4, 5, 6]; const sum = numbers .filter(n => n % 2 === 0) // 짝수 필터링 .map(n => n ** 2) // 제곱 계산 .reduce((acc, cur) => acc + cur, 0); // 합산 console.log("총합:", sum);
TypeScript
복사
두 코드의 결과는 동일하지만, 함수형 코드가 훨씬 간결하고 의도가 명확합니다.
절차지향 코드에서는 여러 중간 변수들이 등장하고, 상태가 계속 변경됩니다. 이런 상태 변화는 코드를 이해하고 디버깅하기 어렵게 만듭니다.
반면 함수형 코드는 데이터가 한 방향으로 흐르는 파이프라인처럼 구성되어, 중간 상태를 숨기고 순수한 데이터 변환 과정만 드러냅니다.

함수형 프로그래밍의 핵심 원칙

함수형 프로그래밍을 이해하기 위해서는 단순히 문법만 익히는 것을 넘어, 프로그래밍을 바라보는 철학적인 관점을 이해하는 것이 중요합니다. 함수형 프로그래밍은 "어떻게(HOW)"가 아닌 "무엇을(WHAT)" 할지를 명확히 표현하는 데 집중합니다. 다음은 함수형 프로그래밍에서 자주 언급되는 핵심 원칙들입니다.

1. 순수 함수(Pure Function)

순수 함수는 다음 세 가지 조건을 만족합니다.
1.
입력값이 같으면 항상 같은 결과를 반환
2.
함수 외부 상태에 의존하지 않음
3.
부작용(side effect)이 없음
function add(a, b) { return a + b; } add(3, 4); // 언제나 7 반환
TypeScript
복사
순수 함수는 예측 가능하고 테스트가 쉬우며, 코드의 안정성을 높여줍니다.

2. 불변성(Immutability)

함수형 프로그래밍에서는 기존 데이터를 절대 직접 수정하지 않습니다.
대신 기존 데이터를 수정하지 않고 새로운 데이터를 생성합니다.
const arr = [1, 2, 3]; const newArr = [...arr, 4];
TypeScript
복사
const person = { name: 'John', age: 30 }; const updatedPerson = { ...person, age: 31 };
TypeScript
복사
데이터의 불변성을 유지하면, 상태 변경을 방지해 예측 가능한 코드를 만듭니다.

3. 고차 함수(Higher-Order Function)

고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수를 말합니다.
함수가 일급 객체로 취급되기 때문에 가능한 문법입니다.
function applyOperation(a, b, callback) { return callback(a, b); } function add(a, b) { return a + b; } const result = applyOperation(3, 4, add); console.log(result); // 7
TypeScript
복사
이 구조는 콜백 함수, map, filter, reduce 같은 API의 기반이 됩니다.
setTimeout( () => { console.log("Hello!"); }, 1000 ); const button = document.getElementById('myButton'); button.addEventListener('click', function() { console.log('Hello!'); } );
TypeScript
복사
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; console.log( arr .filter(num => num % 2 === 0) .map(num => num * num) .reduce((acc, num) => acc + num, 0) ); // 220
TypeScript
복사

4. 선언형 프로그래밍 (Declarative Programming)

절차지향은 “어떻게 할 것인가(HOW)”를 단계별로 명령하지만, 선언형은 “무엇을 할 것인가(WHAT)”를 명확하게 표현합니다.
// 절차지향 방식 let sum = 0; for (let i = 0; i < numbers.length; i++) { sum += numbers[i]; } // 선언형 방식 const sum = numbers.reduce((a, b) => a + b);
TypeScript
복사
선언형 코드는 의도가 더 분명해서 읽고 유지보수하기 쉽습니다.

5. 함수 합성 (Function Composition)

작은 함수들을 조합해 더 복잡한 동작을 수행하는 함수로 만듭니다.
const compose = (f, g) => x => f(g(x)); const addOne = x => x + 1; const double = x => x * 2; const addOneThenDouble = compose(double, addOne); console.log(addOneThenDouble(3)); // 8
TypeScript
복사
함수 합성은 코드를 모듈화하고 재사용성을 높입니다.

정리

함수형 프로그래밍의 핵심 철학은 다음과 같습니다.
1.
순수 함수불변성으로 예측 가능하고 안정적인 코드를 작성합니다.
2.
고차 함수함수 합성으로 유연하고 재사용 가능한 코드를 만듭니다.
3.
선언형 스타일로 코드의 의도를 명확하게 표현합니다.

참고 자료