함수형 프로그래밍, 도대체 뭐길래 다들 좋다고 할까요? 🤔 핵심 원칙 쉽게 파헤치기!

홍태극·2025년 4월 16일
0

함수형 프로그래밍, 도대체 뭐길래 다들 좋다고 할까요? 🤔 핵심 원칙 쉽게 파헤치기!

요즘 개발 씬에서 함수형 프로그래밍(Functional Programming, 줄여서 FP) 이야기가 정말 많이 들려오죠? 명령형이나 객체 지향 프로그래밍(OOP)과는 뭔가 다른 방식이라는데... "그래서 그게 뭔데?" 하고 궁금해하시는 분들이 많을 것 같아요. 어렵게 느껴질 수도 있지만, 알고 보면 복잡한 문제를 더 깔끔하고 예측 가능하게 푸는 데 도움을 주는 아주 매력적인 접근 방식이랍니다! 😊

오늘은 함수형 프로그래밍이 도대체 무엇인지, 어떤 핵심 원칙들을 가지고 있는지, 장단점은 뭔지, 그리고 어디에 많이 쓰이는지! 핵심만 쏙쏙 뽑아서 최대한 쉽고 재미있게 알려드릴게요!

함수형 프로그래밍? 그거 먹는 건가요? 🍚

함수형 프로그래밍은요, 간단히 말해서 프로그램을 순수한 함수들의 조합으로 만들려는 생각이에요. 여기서 '순수한 함수'가 아주 중요한데요. 마치 수학 시간에 배우는 함수처럼, 입력값이 같으면 항상 같은 결과가 나오고, 함수 바깥 세상에 영향을 주지 않는(부수 효과가 없는) 녀석들을 말해요.

우리가 흔히 짜는 명령형 프로그래밍(이거 하고, 저거 하고 순서대로 명령)이나 객체 지향 프로그래밍(객체들이 서로 상태를 바꾸며 상호작용)과는 조금 다른 관점이죠. 함수형 프로그래밍은 '상태 변화'를 최대한 피하고, '데이터'는 바꾸지 않는(불변성) 것을 중요하게 생각해요.

함수형 프로그래밍의 핵심 원칙 3가지 (이것만 알면 반은 성공!)

함수형 프로그래밍의 세계를 이해하려면 꼭 알아야 할 세 가지 기둥이 있어요!

1. ✨ 순수함의 결정체! 순수 함수 (Pure Functions)

이름 그대로 아주 '순수한' 함수예요. 두 가지 중요한 특징이 있죠.

  • 같은 입력에는 항상 같은 출력
    언제, 어디서 호출하든 똑같은 값을 넣어주면 반드시 똑같은 결과가 나와야 해요. 마치 자판기에 같은 돈을 넣으면 항상 같은 음료수가 나오는 것처럼요!

  • 부수 효과(Side Effect) 없음
    함수가 자기 할 일만 딱 하고 끝나야 해요. 함수 바깥에 있는 변수를 바꾸거나, 파일을 쓰거나, 네트워크 요청을 보내는 등 외부에 영향을 주는 '딴짓'을 하면 안 돼요.

// 이건 순수 함수예요! 👍
// 언제 어디서든 add(2, 3)은 항상 5를 반환하고, 다른 곳에 영향을 주지 않아요.
function add(a, b) {
  return a + b;
}

// 이건 순수하지 않아요! 🙅‍♀️
let totalScore = 100; // 함수 바깥에 있는 변수

function addScore(score) {
  totalScore += score; // 바깥의 totalScore를 변경시키네요! (부수 효과 발생)
  return totalScore;
}

순수 함수로 코드를 짜면 좋은 점은요? 결과를 예측하기 쉽고 테스트하기가 정말 편해져요! 언제 불러도 똑같이 행동하니까요.

2. 🧊 한번 정하면 바꾸지 않아! 불변성 (Immutability)

데이터를 '절대 바꾸지 않는다'는 원칙이에요. 만약 데이터에 변화가 필요하다면, 원본을 직접 고치는 게 아니라 변화된 내용을 담은 새로운 데이터 복사본을 만드는 거죠. 마치 사진 원본은 그대로 두고, 편집할 때는 복사본을 만들어서 작업하는 것과 같아요.

// 불변성을 지키는 좋은 예시 (원본 배열은 그대로!)
const originalNumbers = [10, 20, 30];
// ...originalNumbers 로 원본 내용을 복사하고, 40을 추가한 '새로운' 배열 만들기
const newNumbers = [...originalNumbers, 40];

console.log('원본 배열', originalNumbers); // [10, 20, 30] (변하지 않았어요!)
console.log('새로운 배열', newNumbers);    // [10, 20, 30, 40]

// 이건 불변성을 어기는 예시 (원본 배열이 바뀌어요!)
const mutableNumbers = [10, 20, 30];
mutableNumbers.push(40); // 원본 배열에 직접 40을 추가!

console.log('원본이 바뀐 배열', mutableNumbers); // [10, 20, 30, 40]

데이터를 직접 바꾸지 않으면 뭐가 좋을까요? 데이터가 여기저기서 예기치 않게 변하는 걸 막을 수 있어서 버그가 줄어들고 코드를 이해하기 쉬워져요. 특히 여러 작업이 동시에 데이터를 건드릴 수 있는 병렬 처리 환경에서 아주 강력한 힘을 발휘한답니다! (데이터 꼬일 걱정 뚝!)

3. 🥇 함수도 값이다! 일급 객체와 고차 함수 (First-Class & Higher-Order Functions)

함수형 프로그래밍에서는 함수를 숫자나 문자열처럼 그냥 하나의 '값'으로 취급해요. 이걸 일급 객체(First-Class Citizen) 라고 불러요. 그래서 함수를 변수에 담을 수도 있고, 다른 함수에 인자로 넘겨줄 수도 있고, 함수가 결과값으로 또 다른 함수를 돌려줄 수도 있죠.

그리고 함수를 인자로 받거나, 함수를 결과로 돌려주는 함수를 특별히 고차 함수(Higher-Order Function) 라고 불러요. 우리가 자바스크립트에서 즐겨 쓰는 map, filter, reduce 같은 배열 메서드들이 바로 대표적인 고차 함수랍니다!

// 1. 함수를 변수에 담기
const sayHello = function(name) {
  return `안녕, ${name}!`;
};
console.log(sayHello('함수')); // "안녕, 함수!"

// 2. 함수를 인자로 넘기기 (고차 함수 map 사용)
const numbers = [1, 2, 3];
// 각 숫자를 제곱하는 함수를 map의 인자로 전달!
const squaredNumbers = numbers.map(function(x) { return x * x; });
// 화살표 함수로 더 간결하게! const squaredNumbers = numbers.map(x => x * x);
console.log(squaredNumbers); // [1, 4, 9]

// 3. 함수를 결과로 돌려주기 (고차 함수)
function createGreeter(greeting) {
  // 인사말을 받아서, 이름을 받아 인사하는 '함수'를 만들어 돌려줌
  return function(name) {
    return `${greeting}, ${name}!`;
  };
}

const greetInKorean = createGreeter('안녕하세요'); // '안녕하세요' 인사말을 기억하는 함수가 만들어짐
console.log(greetInKorean('여러분')); // "안녕하세요, 여러분!"

고차 함수를 잘 활용하면 코드가 훨씬 간결해지고 재사용성도 높아져요. 작은 함수들을 레고 블록처럼 조립해서 더 복잡한 기능을 만들 수 있거든요.

👍 그래서 함수형으로 짜면 뭐가 좋은데요? (장점)

이런 원칙들 덕분에 함수형 프로그래밍은 여러 가지 장점을 가져요.

  • 예측 가능 & 쉬운 테스트
    순수 함수는 믿을 수 있으니 코드가 어떻게 돌아갈지 예측하기 쉽고, 테스트 코드 짜기도 훨씬 수월해요.

  • 동시성/병렬 처리 유리
    데이터 불변성 덕분에 여러 작업이 동시에 돌아가도 데이터 꼬일 걱정이 적어서 요즘처럼 멀티코어 CPU가 흔한 시대에 딱 좋아요!

  • 간결하고 재사용성 높은 코드
    고차 함수 등으로 코드를 짧고 명료하게 쓸 수 있고, 작은 함수들을 여기저기 다시 쓰기 좋아요.

  • 쉬운 유지보수
    코드가 명확하고 부수 효과가 적으니 버그 찾기도 쉽고, 수정하기도 편해요.

🤔 물론, 고려할 점도 있어요 (단점/고려사항)

세상에 완벽한 건 없듯이 함수형 프로그래밍에도 신경 써야 할 부분들이 있어요.

  • 배우기 좀 어려울 수 있어요
    명령형이나 객체 지향 방식에 익숙하다면 순수 함수, 불변성, 모나드(?) 같은 개념들이 처음엔 좀 낯설고 어렵게 느껴질 수 있어요. (하지만 핵심 원칙부터 차근차근 익히면 괜찮아요!)

  • 성능 이슈 (가끔)
    데이터를 계속 복사(불변성)하다 보면 메모리를 더 많이 쓰거나 가비지 컬렉션(안 쓰는 메모리 정리) 부담이 늘어날 수도 있어요. (물론 요즘 언어들은 많이 최적화되어 있어서 큰 문제가 안 되는 경우도 많아요.)

  • 디버깅이 까다로울 수도
    함수 호출이 계속 이어지거나 재귀가 깊어지면 에러가 났을 때 어디서 문제가 시작됐는지 추적하기가 조금 복잡할 수 있어요.

🚀 어디서 많이 쓰이나요? (활용 분야)

함수형 프로그래밍은 생각보다 우리 주변 가까이에 많이 쓰이고 있어요!

  • 순수 함수형 언어
    Haskell, F# 같은 언어는 아예 함수형으로만 코딩하도록 설계되었어요.

  • 요즘 대세 언어들
    JavaScript, Python, Scala, Kotlin, Swift 등 많은 현대 언어들이 함수형 프로그래밍 기능을 품고 있어서, 필요에 따라 함수형 스타일로 코드를 짤 수 있어요.

  • 프론트엔드
    React (특히 Hooks), Redux, Zustand 같은 라이브러리/프레임워크들은 복잡한 UI 상태 관리를 위해 함수형 원칙(불변성 등)을 적극적으로 활용해요.

  • 데이터 처리
    대용량 데이터를 다루는 빅데이터 처리나 실시간 스트림 처리에서도 함수형 접근 방식이 빛을 발해요. 데이터를 변환하고 처리하는 데 아주 효과적이거든요.

  • 병렬/분산 처리
    여러 컴퓨터나 코어에서 동시에 작업을 돌릴 때 데이터 불변성 덕분에 안전하게 처리할 수 있어서 많이 사용돼요.

✨ 함수형 프로그래밍, 꼭 써야 할까요? (마무리)

함수형 프로그래밍은 그냥 유행하는 기술이 아니라, 복잡한 소프트웨어를 더 안정적이고 예측 가능하게 만들기 위한 강력한 생각의 도구예요. 모든 문제를 함수형으로만 풀어야 한다는 건 아니지만, 그 속에 담긴 핵심 원칙(순수 함수, 불변성)들을 이해하고 코드에 조금씩 적용해보는 것만으로도 코드의 품질을 높이고 개발 생산성을 향상시키는 데 정말 큰 도움이 될 거예요!

오늘 함수형 프로그래밍에 대해 조금이나마 감을 잡으셨기를 바라며, 혹시 더 궁금한 점이나 여러분의 경험담이 있다면 댓글로 자유롭게 나눠주세요! 😊

0개의 댓글