'함수형 프로그래밍'은 함수형이라는 이름으로 인해 많은 오해를 불러일으킵니다. 가장 흔한 오해는 함수형 프로그래밍의 반대는 '객체 지향 프로그래밍'이라는 생각입니다. 이외에도 함수형 프로그래밍에 대한 오해는 꽤 많습니다. 그래서 오늘 이 글에서 함수형 프로그래밍이 무엇인지에 대해 설명하고, 관련한 오해를 풀어보려합니다. 먼저 함수형 프로그래밍과 관련한 여러 프로그래밍 관점들을 소개하겠습니다.
절차 지향 vs 함수형 vs 객체 지향
✅ 절차 지향 프로그래밍 (Procedural Programming)
- 핵심 개념: 프로그램을 순차적인 절차(명령의 흐름)로 구성하여 문제를 해결함.
- 기반 구조: 함수(또는 프로시저)를 사용하여 코드를 구조화하되, 주로 전역 상태와 공유된 데이터를 중심으로 동작.
- 대표 언어: C, Pascal, Fortran 등
특징:
- 명령어들이 순서대로 실행됨 (절차적 흐름 중요)
- 상태 변화(변수 변경)를 자유롭게 함
- 가변 데이터를 많이 사용
- 함수는 보조 도구이며, 상태를 변경하거나 입출력을 수행함
예시:
let total = 0;
function addToTotal(num) {
total += num;
}
addToTotal(5);
console.log(total); // 5 (상태 변화)
위 예시에서 단순히 함수 addToTotal을 만들고 이를 사용했으니 함수형 프로그래밍이 아니냐?라고 생각할 수 있습니다. 하지만 이는 함수형 프로그래밍이 아닙니다. 그 이유는 다음과 같습니다.
- 함수형 프로그래밍이 아닌 이유
- 외부 상태 변경
전역 변수인 total을 함수 내부에서 변경하고 있습니다. 이렇게 외부 상태를 변경하는 것은 함수형 프로그래밍 철칙에 위배됩니다. - 새로운 값 반환 안함
함수형 프로그래밍에서는 새로운 값을 만들고 이를 반환해야합니다. 하지만 위 addToTotal은 단순히 외부 상태인 total 변수만 수정하고 새로운 값을 만들거나 반환하지 않고 있습니다.
- 외부 상태 변경
✅ 함수형 프로그래밍 (Functional Programming)
- 핵심 개념: 프로그램을 수학적 함수처럼 구성하며, 상태와 부작용을 최소화함.
- 기반 구조: 순수 함수(Pure Function)를 중심으로 프로그램을 구성
- 대표 언어: Haskell, Clojure, Elm, (함수형 기능이 있는 JavaScript, Python, Scala 등)
특징:
- 순수 함수(Pure function)
순수 함수 사용하여 같은 입력에 대해 항상 같은 출력을 보장함. 외부 상태를 변경하지 않음 - 불변성(immutability)
외부 상태를 변경하지 않고, 새로운 값을 생성함 - 고차 함수 사용
함수를 인자로 받거나 반환하는 함수 - 상태와 부작용을 최소화하여 디버깅과 테스트가 용이함
예시:
function add(a, b) {
return a + b;
}
const result = add(3, 5); // 항상 8
console.log(result); // 8 (불변, 순수 함수)
위에서 설명한 절차 지향 프로그래밍과 어디가 달라졌을까요?
- 함수형 프로그래밍인 이유
- 외부 상태 변경
외부 상태를 변경하지 않습니다. 만약 add 함수 내부에서 외부에서 전달된 a, b값을 수정했다면 함수형 프로그래밍 철칙을 위배합니다. - 새로운 값 반환
a와 b를 더한 새로운 값을 반환하고 있습니다.
- 외부 상태 변경
✅ 객체 지향 프로그래밍 (Object-Oriented Programming)
- 핵심 개념: 현실 세계의 개념을 객체(object)로 모델링하여, 객체 간의 상호작용으로 프로그램을 구성함
- 기반 구조: 클래스(class)와 객체(instance)를 중심으로 프로그램을 구성
- 대표 언어: Java, C++, C#, Python, Ruby, Kotlin, Swift 등
특징:
- 캡슐화(Encapsulation)
데이터(속성)와 동작(메서드)을 하나의 객체 안에 묶어 외부에 불필요한 내부 구현을 숨김 - 상속(Inheritance)
상위 클래스의 속성과 동작을 하위 클래스가 물려받아 재사용성과 확장성을 높임 - 다형성(Polymorphism)
동일한 인터페이스나 메서드가 여러 클래스에서 다르게 동작할 수 있게 함 (오버라이딩, 오버로딩) - 추상화(Abstraction)
복잡한 내용을 숨기고, 필수적인 요소만 외부에 제공하여 복잡도를 줄임
예시:
class Adder {
constructor(a, b) {
this.a = a;
this.b = b;
}
add() {
return this.a + this.b;
}
}
// 객체 생성
const myAdder = new Adder(3, 5);
// 메서드 호출
const result = myAdder.add(); // 8
console.log(result);
위에서 설명한 함수형 프로그래밍과 다른 점이 확실히 보일 것입니다. 객체 지향 프로그래밍에서는 하나의 역할과 책임을 담당하는 class를 만들기 때문에 위와 같이 Adder라는 클래스를 만들고 해당 클래스 내부에 add라는 메서드를 만드는 방식을 이용합니다.
함수형 프로그래밍에 대한 오해
1. 함수형(or 절차지향) 프로그래밍의 반대는 객체지향 프로그래밍이다?
함수형 프로그래밍과 객체 지향 프로그래밍은 정반대의 개념이라고 생각하시는 분들이 많습니다. 혹은 절차 지향 프로그래밍과 객체 지향 프로그래밍이 정반대 개념이라고 생각하시는 분들도 있습니다. 각 프로그래밍 철학이 서로 다른 관점을 가지고 있는 것은 맞지만, 정확히 정반대의 개념을 가지고 있어 혼용될 수 없다는 이야기는 틀렸다고 볼 수 있습니다.
예를 들어 객체 지향 프로그래밍은 객체(클래스)라는 존재를 이용해 객체 간 관계를 중심으로 코드를 작성하겠다는 뜻입니다. 이때 전체적인 도메인 모델링만 객체 지향 프로그래밍 관점을 활용하고, 객체에 대한 데이터 처리 로직 과정에는 함수형 프로그래밍을 적극 활용하면 객체 지향 프로그래밍과 함수형 프로그래밍을 동시에 사용하는 것이죠.
2. map, filter 같은 것만 사용하면 함수형 프로그래밍인가요?
map이나 filter와 같은 함수를 사용해도 내부에서 객체의 프로퍼티를 직접 수정하는 경우는 이를 함수형 프로그래밍이라고 할 수 없습니다. 간단한 예시입니다.
// ❌ 불변성 위반 예시
const users = [{ name: "Alice", active: true }];
const deactivated = users.map(u => {
u.active = false; // 원본 변경!
return u;
});
위 예시에서는 users라는 배열을 순회하면서 active 프로퍼티 값을 바꾸도록 설정되어 있습니다. 이는 함수형 프로그래밍의 철칙인 불변성(immutability)를 위배하므로 함수형 프로그래밍이라고 볼 수 없습니다.
3. Java, Python, Javascript로 함수형 프로그래밍이 가능한가요?
위 언어로도 함수형 프로그래밍이 가능은 합니다. 하지만 여기서 조심해야할 것은 위 언어는 함수형 언어는 아니라는 점입니다. 즉, 함수형 프로그래밍을 위한 기능을 지원하지만 제한적이라는 것입니다. 더 확실한 함수형 프로그래밍을 위해서는 Haskell, Elm 같은 함수형 프로그래밍에 최적화된 언어를 사용하는 것이 좋습니다.
'CS 상식 > 소프트웨어 공학' 카테고리의 다른 글
ESLint, Prettier 기초부터 실전 적용까지 - Node 개발자 필수 상식 (0) | 2025.05.01 |
---|---|
저장 장치의 기본 개념 - 디스크, 드라이브, 파티션, 파일 시스템에 대해 알고가자( 리눅스 vs 윈도우 ) (0) | 2025.03.19 |
[JS] 값을 복사하는 여러 방법과 차이점 - 얕은 복사 / 깊은 복사 (0) | 2025.01.29 |
[면접 단골 질문] 동시성과 병렬성 차이는 무엇인가요? (0) | 2025.01.08 |