ABOUT

성능과 운영 안정성을 함께 끌어올리는 개발자입니다.

92% Positional Error Reduction
79% p95 Latency Improvement
90%+ Long Tasks Reduction

2022.02 · 한국장학재단

우수 멘티

한국장학재단 사회 리더 대학생 멘토링 IT

2022.10 · 동작구청

우수 인재상

동작구청 우수 SW 인재

2025.05 · (주) 그랩

프로그래밍 우수상

(주) 그랩 우수 프로그램 개발

2025.05 · AWSKRUG

AWS한국사용자모임 발표

AI agent 스크립트 튜닝 관련 발표

ComputerScience

Development

Engineering

Trouble Shooting

GUESTBOOK

첫 마음부터
함께 나누는 온기

방명록 작성하러 가기

SUBSCRIBE

최신소식을
편하게 만나보세요.

함수형 프로그래밍 (FP)

도입

“상태 변경을 줄이고, 예측 가능한 로직”을 만드는 방식입니다.

백엔드 개발에서 버그의 상당수는 “계산이 틀려서”가 아니라, 상태가 예상과 다르게 바뀌어서 발생합니다.

동시성 환경에서는 이 문제가 더 심해지는데 이러한 위험을 줄이기 위해 불변성(immutability), 순수 함수(pure function), 부수 효과(side effect) 제어에 집중합니다.

핵심 메시지

“함수형은 언어가 아니라 사고방식이다.
상태를 줄이면 테스트와 운영이 쉬워진다.”

- 실무에서 FP를 쓰는 이유 -

정의

함수를 1급 객체(first-class citizen)로 다루고, 부수효과를 최소화하며
불변 데이터를 중심으로 프로그램을 구성하는 패러다임입니다.

“함수형 = 재귀/람다/스트림” 같은 기술로만 이해하면 실무 적용이 어려워집니다.

핵심은 결과가 예측 가능한 코드(Deterministic)를 만드는 것입니다.

핵심 개념

실무에서 가장 중요한 4가지는 순수 함수, 불변성, 부수효과 분리, 함수 합성입니다.
개념 키워드 실무 의미
순수 함수 Pure 같은 입력 → 항상 같은 출력, 외부 상태/IO에 의존하지 않음
불변성 Immutable 상태 변경 대신 새 값 생성 → 동시성/버그 위험 감소
부수효과 Side Effect DB/네트워크/로그 같은 효과는 “경계”로 모아 통제
합성 Compose 작은 함수를 조합해 큰 로직 구성(재사용/테스트 쉬움)

 

순수 함수

순수 함수는 테스트하기 쉬운 코드를 만드는 가장 강력한 방법입니다.

예: “주문 총액 계산”은 DB나 시간에 의존하지 않고 계산만 하면 됩니다. 이런 로직은 순수 함수로 분리하면 테스트가 매우 간단해집니다.

// 순수 함수 예시(개념) // - 외부 상태 접근 없음 // - 동일 입력 → 동일 출력 int calcTotalPrice(List<OrderLine> lines) { int sum = 0; for (OrderLine l : lines) sum += l.price() * l.qty(); return sum; }

 

불변성

불변(Immutable)은 “동시성”과 “예측 가능성”을 같이 해결합니다.

가변 상태가 공유되면(예: static Map, 전역 캐시) 어디서 값이 바뀌었는지 추적하기 어렵고, 멀티스레드에서 레이스 컨디션이 발생합니다. 불변 객체는 생성 후 상태가 바뀌지 않으니 공유해도 안전하고, 로그/디버깅도 쉬워집니다.

// 불변 객체 개념 예시 final class Money { private final int amount; Money(int amount) { this.amount = amount; } int amount() { return amount; } Money plus(Money other) { return new Money(this.amount + other.amount); } }

 

부수효과(Side Effect) 분리

실무에서는 “순수 로직”과 “IO(DB/HTTP/로그)”를 경계로 분리하는 것이 핵심입니다.

백엔드에서 부수효과는 보통 DB 저장, 외부 API 호출, 메시지 발행, 로그 기록입니다. 이들을 로직 중간에 섞어버리면 테스트가 어렵고, 장애 시 영향 범위가 커집니다. 반대로 “순수 로직은 계산만” 하고, “부수효과는 마지막에 한 곳에서” 처리하면 설계가 단단해집니다.

💡 TIP / “순수 계산 → 마지막에 저장”

가장 쉬운 FP 적용법은 (1) 계산 로직을 순수 함수로 분리하고, (2) 저장/발행 같은 IO는 애플리케이션 서비스 끝에서 수행하는 구조입니다. 이 방식은 DDD의 “도메인 모델(순수 규칙) vs 인프라(IO)” 분리와도 잘 맞습니다.

 

함수 합성 & 컬렉션 처리

작은 함수를 조합해 큰 로직을 만드는 습관은 유지보수성을 크게 올립니다.

Java에서는 Stream API가 대표적입니다. 필터/매핑/집계가 “선언적”으로 표현되어 읽기 쉬워지고, 중간 변수를 줄여 부수효과를 줄일 수 있습니다.

// 컬렉션 처리 예시(개념) int total = lines.stream() .filter(l -> l.qty() > 0) .mapToInt(l -> l.price() * l.qty()) .sum();

 

백엔드에서 언제 쓰면 좋은가

“규칙 계산”과 “상태 변경”을 분리해야 하는 순간에 FP가 특히 강합니다.
상황 FP 적용 포인트
도메인 규칙 계산 순수 함수로 분리 → 단위 테스트 쉬움
동시성/멀티스레드 불변 객체 사용 → 경쟁 조건 감소
테스트 강화 IO 분리 → Mock/Fake 범위 축소
리팩터링 함수 합성/작은 단위 분리 → 변경 영향 최소화

 

자주 하는 오해

FP는 “무조건 Stream/람다로 바꾸기”가 아니라 “부수효과 통제”가 핵심입니다.

BAD

  • Stream 남발로 디버깅/가독성 악화
  • IO(DB/HTTP)를 람다 체인 중간에 섞음
  • 불변을 지킨다고 복사 비용이 과도해짐

GOOD

  • 순수 계산 로직만 함수형 스타일로 분리
  • IO는 경계(서비스 끝/인프라 레이어)에 모아 통제
  • 불변 객체는 “핵심 값”부터 적용

 

정리

함수형 프로그래밍은 상태를 줄이고 예측 가능성을 높여, 테스트와 운영을 쉬워지게 만드는 실무형 설계 도구입니다.

✅ 핵심 요약

  • ✔️ FP의 핵심은 순수 함수 + 불변성 + 부수효과 분리입니다.
  • ✔️ 백엔드에서는 “규칙 계산”을 순수 함수로 분리하는 것만으로도 효과가 큽니다.
  • ✔️ IO(DB/네트워크)는 경계로 모아 통제하면 테스트/장애 대응이 쉬워집니다.
  • ✔️ FP는 전면 도입보다 “문제 많은 지점부터 점진 적용”이 현실적입니다.
728x90