함수형 프로그래밍(Functional Programming)이란 무엇인가요?

김상욱·2024년 11월 14일

함수형 프로그래밍(Functional Programming)이란 무엇인가요?

함수형 프로그래밍은 함수를 일급 객체로 취급하며, 상태와 변경을 피하고 순수 함수를 중심으로 프로그램을 구성하는 패러다임입니다. 수학적 함수의 개념에 기반하여 프로그래밍을 수행하며, 주로 선언형(Declarative) 프로그래밍 스타일을 따릅니다.

함수의 일급 객체(First-Class Citizien)

  • 함수는 변수에 할당하거나, 인수로 전달하거나, 반환값으로 사용할 수 있습니다.
const add = (a, b) => a + b;
const apply = (func, x, y) => func(x, y);
console.log(apply(add, 2, 3)); // 5

순수 함수(Pure Function)

  • 동일한 입력값에 대해 항상 동일한 출력값을 반환하며, 함수 외부 상태를 변경하지 않습니다. 즉, 함수가 실행될 때 함수 외부에 존재하는 변수, 객체, 데이터 구조 등의 값을 직접 수정하지 않는다는 것을 의미.
    비순수 함수
let counter = 0;

function increment() {
    counter += 1; // 외부 변수 counter를 직접 변경
    return counter;
}

console.log(increment()); // 1
console.log(increment()); // 2

순수 함수

function increment(counter) {
    return counter + 1; // 외부 상태를 변경하지 않고, 새로운 값을 반환
}

let counter = 0;

console.log(increment(counter)); // 1
console.log(increment(counter)); // 1 (외부 상태는 변하지 않음)
counter = increment(counter); // 새로운 값을 외부에서 할당
console.log(counter); // 1

순수 함수를 사용하는 이유는

  • 함수가 외부 상태를 수정하면, 함수 호출 결과가 외부 상태에 의존하게 됩니다. 상태가 많아질수록 프로그램의 동작을 예측하기 어려워집니다.
  • 외부 상태를 수정하지 않으면, 입력값만으로 결과를 예측할 수 있어 테스트가 쉽습니다.
  • 외부 상태를 변경하지 않으면, 동시에 실행되는 다른 코드와 충돌하지 않습니다. 이를 통해 병렬 처리와 멀티스레드 환경에서의 안정성을 보장할 수 있습니다.
  • 외부 상태를 수정하는 함수는 원인을 추적하기 어렵지만 순수함수는 함수 내부의 로직만 확인하면 되므로 디버깅이 간단합니다.

함수형 프로그래밍은 불변성(Immutability)를 띕니다.

  • 데이터를 변경하지 않고, 변경이 필요한 경우 새로운 데이터를 생성합니다. 상태를 직접 수정하지 않기 때문에 예측 가능성이 높아집니다.

고차 함수(Higher-order Function)

  • 함수를 매개변수로 받거나, 함수를 반환하는 함수
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((n) => n * 2); // [2, 4, 6, 8]
console.log(doubled);

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

  • 무엇을 해야하는지(What to do)를 설명하며, 명령형 프로그래밍처럼 어떻게(How to do)를 상세히 기술하지 않습니다.
    명령형(Imperative Programming) : 프로그램의 실행 흐름을 명확히 지시하며, 단계별 절차를 중심으로 작성. 즉, 수행할 작업하나하나를 직접 명령
const numbers = [1, 2, 3, 4, 5];
const evens = [];

for (let i = 0; i < numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        evens.push(numbers[i]); // 조건에 맞는 값을 추가
    }
}

console.log(evens); // [2, 4]

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

  • 프로그램의 목적과 결과에 초점을 맞추며, 실행 방법은 추상화 됩니다. 실행 로직은 내부적으로 처리되므로, 개발자는 코드의 의도만 표현하면 됩니다.
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter((n) => n % 2 === 0);

console.log(evens); // [2, 4]

함수형 프로그래밍은 지연 계산(Lazy Evaluation)을 사용

  • 값을 즉시 계산하지 않고, 필요한 순간에만 계산 즉, 연산 결과를 나중에 사용할 수도 있지만, 아직 참조되지 않은 값은 계산x -> 모든 작업이 수행되지 않고도, 프로그램이 실행을 계속 진행할 수 있다.
    ex) Java Stream API의 지연 계산 - map(), filter()와 같은 중간 연산은 즉시 실행되지 않으며, 최종 연산(forEach(), coolect())을 호출할 때 실행.

이러한 함수형 프로그래밍을 왜 사용하는가?

  • 선언형 스타일로 작성되므로 코드를 이해하기 쉽습니다.
  • 테스트 용이성 : 순수 함수는 외부 상태를 다루지 않으므로 테스트가 간단.
  • 불변성 덕분에 상태 충돌 없이 병렬 처리가 가능
  • 부작용이 없으므로 원인 추적이 용이.

함수형 프로그래밍(Functional Programming)은 순수 함수, 불변성, 고차 함수를 기반으로 프로그램을 작성하며, 상태와 변경을 최소화하여 코드의 예측 가능성과 테스트 가능성을 높이는 프로그래밍 패러다임입니다.

백엔드 개발자로 취업을 준비하며 함수형 프로그래밍을 실습할 수 있는 여러 가지 방법이 있습니다. 실습을 통해 함수형 프로그래밍의 원칙과 이를 백엔드 개발에 적용하는 방법을 익힐 수 있습니다.


실습을 통해 배우기 좋은 주제들

1. Java Stream API를 활용한 데이터 처리

Java 8부터 도입된 Stream API는 함수형 프로그래밍의 핵심 요소를 제공합니다. 데이터를 처리하는 데 함수형 스타일(filter, map, reduce)을 사용할 수 있습니다.

실습 과제:

  • 사용자 데이터 목록에서 특정 조건에 맞는 사용자 필터링
  • 주문 목록의 총 가격 계산
  • 중첩된 데이터를 플랫하게 변환 (flatMap)
import java.util.Arrays;
import java.util.List;

public class StreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

        // 짝수만 필터링 후 두 배로 변환
        numbers.stream()
                .filter(n -> n % 2 == 0)
                .map(n -> n * 2)
                .forEach(System.out::println);
    }
}

2. Optional을 이용한 Null 처리

Optional은 함수형 프로그래밍에서 흔히 사용하는 모나드(Monad) 개념을 Java에 구현한 것으로, NullPointerException을 방지하는 데 유용합니다.

실습 과제:

  • 사용자 정보를 찾고, 값이 없으면 기본값 반환
  • 데이터를 처리하면서 null 체크 대신 Optional 사용
import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        Optional<String> name = Optional.ofNullable(null);

        // 값이 있으면 출력, 없으면 기본값 사용
        String result = name.orElse("Default Name");
        System.out.println(result);
    }
}

3. Lambda와 Functional Interface

Java의 람다식과 FunctionalInterface는 함수형 프로그래밍을 위한 기본 도구입니다. 이를 활용해 코드 간소화와 가독성 향상을 실습합니다.

실습 과제:

  • 커스텀 FunctionalInterface를 만들어 활용
  • 다양한 함수 조합(compose, andThen) 실습
import java.util.function.Function;

public class LambdaExample {
    public static void main(String[] args) {
        Function<Integer, Integer> multiplyByTwo = x -> x * 2;
        Function<Integer, Integer> addThree = x -> x + 3;

        // 함수 조합
        Function<Integer, Integer> combined = multiplyByTwo.andThen(addThree);

        System.out.println(combined.apply(5)); // 13
    }
}

4. Spring에서의 함수형 프로그래밍

Spring WebFlux는 함수형 프로그래밍 스타일을 적극적으로 활용합니다. Mono, Flux와 같은 Reactor 라이브러리를 사용하면 비동기 및 리액티브 프로그래밍 실습이 가능합니다.

실습 과제:

  • WebFlux로 비동기 REST API 구현
  • Flux를 사용한 데이터 스트림 처리
  • 리액티브 프로그램에서 지연 계산 이해
import reactor.core.publisher.Flux;

public class WebFluxExample {
    public static void main(String[] args) {
        Flux.just(1, 2, 3, 4)
                .filter(n -> n % 2 == 0)
                .map(n -> n * 2)
                .subscribe(System.out::println); // 4, 8
    }
}

5. 명령형 코드 vs 함수형 코드 비교

같은 기능을 명령형 방식과 함수형 방식으로 작성하고, 차이를 비교해 보는 것도 실습에 유용합니다.

실습 과제:

  • 명령형 방식으로 작성된 코드 리팩토링하기
  • 데이터 정렬, 필터링, 집계 등의 작업을 함수형 방식으로 변환

실습 주제를 활용한 프로젝트 아이디어

  1. 로그 분석기

    • 대용량 로그 데이터를 처리하여 특정 키워드 필터링, 요약 및 통계를 생성.
    • Stream API와 Collectors를 활용.
  2. 도서 관리 API

    • WebFlux 기반의 비동기 REST API 구현.
    • 사용자 요청 데이터를 Flux로 처리.
  3. 채팅 서비스

    • 사용자 메시지를 실시간 스트림으로 처리하며, WebSocket과 리액티브 프로그래밍을 적용.

실습 방법

  1. 단계별로 진행

    • 먼저 Java 기본 문법과 함수형 프로그래밍의 개념 이해.
    • Stream API, Lambda를 활용한 간단한 실습부터 시작.
    • WebFlux와 같은 실무에 가까운 기술 적용.
  2. 깃허브(GitHub)에 코드 공유

    • 실습한 내용을 깃허브에 업로드하여 포트폴리오로 활용.
  3. 토이 프로젝트 진행

    • 위의 프로젝트 아이디어를 기반으로 간단한 기능을 점진적으로 구현.
  4. 온라인 플랫폼 활용

    • HackerRank, LeetCode, 백준 등에서 함수형 스타일로 문제를 해결.

실습 시 신입 개발자로서의 장점 어필

  • 코드 가독성 향상: 함수형 프로그래밍을 활용해 간결하고 유지보수 가능한 코드를 작성할 수 있음.
  • 테스트 용이성: 순수 함수 기반으로 작성된 코드는 테스트가 쉽고, 신뢰성이 높음을 강조.
  • 최신 기술 활용: Java Stream, WebFlux 등 현대적인 기술을 학습하고 적용한 경험을 보여줌.

실습을 통해 작성한 프로젝트와 코드를 인터뷰나 자기소개서에서 잘 표현하면 함수형 프로그래밍을 실무에 적용할 준비가 된 신입 개발자로 어필할 수 있습니다.

0개의 댓글