[Flutter] 함수형 프로그래밍(Functional Programming)

2025. 5. 14. 01:26Dart & Flutter

Flutter를 배우다 보면 함수형 프로그래밍(Functional Programming, FP)이라는 단어를 접하게 됩니다. 특히 Flutter의 위젯 트리 구조, build() 함수, 콜백 패턴 등은 모두 함수형 스타일의 특징을 가지고 있어요.
이 글에서는 함수형 프로그래밍이란 무엇인지, Dart와 Flutter에서 어떤 방식으로 적용되는지, 예제와 함께 자세히 알아보겠습니다!


함수형 프로그래밍이란?

함수형 프로그래밍은 데이터를 함수로 처리하는 방식의 프로그래밍 패러다임입니다. 부수 효과(Side Effects)를 최소화하고, 함수 자체를 일급 객체로 사용하며, 불변성(Immutability)을 중시합니다.
 
순수 함수(Pure Function): 같은 입력 → 항상 같은 출력, 외부 상태에 의존 X, 부작용 X
불변성(Immutability): 데이터는 변경되지 않고, 복사된 새 객체를 사용
일급 함수(First-Class Functions): 함수를 변수처럼 전달, 리턴, 저장 가능
고차 함수(Higher-Order Function): 함수를 인자로 받거나 함수를 리턴하는 함수
선언형 프로그래밍(Declarative): ‘무엇을 할지’를 선언적으로 작성


Dart는 함수형 언어일까?

Dart는 엄밀히 말하면 멀티 패러다임 언어입니다. 즉, 객체지향과 함수형 둘 다 지원합니다. 그렇기 때문에 Flutter 개발에서도 객체지향(OOP)과 함수형(FP)을 상황에 맞게 조화롭게 사용할 수 있어요.


Flutter는 왜 함수형 스타일을 많이 쓸까?

Flutter의 UI는 build() 함수 내에서 선언적으로 정의됩니다. 화면에 그릴 위젯 트리를 함수 안에서 마치 HTML을 쓰듯 선언하는 방식이죠.

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      Text('안녕하세요'),
      ElevatedButton(
        onPressed: () => print('버튼 클릭'),
        child: Text('클릭'),
      )
    ],
  );
}

 
이처럼 UI를 함수로 표현하고, onPressed 같은 이벤트에 함수를 콜백으로 전달하는 구조는 전형적인 함수형 프로그래밍 방식입니다.


핵심 개념 자세히 보기

1. 순수 함수 (Pure Function)

int add(int a, int b) {
  return a + b;
}

 
• 같은 입력 a, b → 항상 같은 결과
• 외부 상태에 의존하지 않음
• 부수 효과(예: 콘솔 출력, DB 저장) 없음
 
반면 아래 함수는 순수하지 않음:

int count = 0;

int increase() {
  count += 1;
  return count;
}

 
• 외부 변수인 count에 의존 → 순수하지 않음


2. 불변성 (Immutability)

 
Dart에서 final이나 const 키워드를 사용하면 값을 변경하지 못하게 할 수 있어요.

final List<String> fruits = ['apple', 'banana'];
// fruits.add('orange'); // 불가능

final newFruits = [...fruits, 'orange']; // 새로운 리스트 생성

 
Flutter에서는 상태 변경이 일어날 때마다 UI를 다시 재구성(build) 하는데, 이 과정에서도 불변 상태 관리는 매우 중요합니다.


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

 
고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수입니다.

void executeTwice(Function fn) {
  fn();
  fn();
}

void sayHi() => print('Hi!');

void main() {
  executeTwice(sayHi);
}

 
또는 리스트 처리에서도 자주 사용됩니다:

List<int> numbers = [1, 2, 3];
List<int> doubled = numbers.map((n) => n * 2).toList();

4. 익명 함수와 람다식 (Lambda)

 
Flutter에서는 버튼, 제스처, 리스트 등에서 익명 함수(이름 없는 함수)를 자주 사용합니다.

ElevatedButton(
  onPressed: () {
    print('버튼 클릭됨!');
  },
  child: Text('클릭'),
)

 
한 줄로 쓸 땐 더 간단히:

onPressed: () => print('간단한 클릭')

5. 콜백 함수 (Callback)

 
Flutter는 사용자 인터랙션을 함수로 처리합니다. 대표적인 예가 onPressed, onChanged, onTap 등입니다.

TextField(
  onChanged: (value) => print('입력: $value'),
)

 
여기서 (value) => print(...)는 함수형 프로그래밍 스타일의 콜백입니다.


🧱 실제 Flutter 구조에서 FP 스타일 예시

class TodoItem {
  final String title;
  final bool isDone;

  TodoItem({required this.title, required this.isDone});

  TodoItem toggleDone() {
    return TodoItem(title: title, isDone: !isDone);
  }
}

 
• toggleDone()은 원래 객체를 변경하지 않고, 새로운 객체를 리턴합니다. (불변성)
• 이런 스타일은 상태 관리(예: Provider, Riverpod, Bloc)에서도 매우 유용합니다.


Flutter 라이브러리와 함수형 스타일

함수형 스타일을 더 풍부하게 지원하는 라이브러리도 많습니다:
 
dartz: Option, Either, fold, map 등 FP 스타일 함수 제공
fpdart: 더 현대적이고 직관적인 함수형 유틸리티
Flutter_hooks: 리액트처럼 상태를 함수형 방식으로 다룸
Riverpod: 불변 상태를 기반으로 한 FP 스타일의 상태 관리


함수형 vs 객체지향, Flutter에서 어떻게 선택할까?

상황 추천 방식
UI 위젯 구조 작성 함수형 스타일 (선언적 UI)
상태 객체 설계 객체지향 (모델 클래스, 캡슐화)
로직 재사용 함수형 (고차 함수, map/filter 등)
복잡한 앱 구조 OOP + FP 혼합 설계 (ex: BLoC 패턴)


정리

Flutter는 함수형 프로그래밍의 철학을 UI 설계에 깊이 반영한 프레임워크입니다. Dart의 멀티 패러다임 특성 덕분에 객체지향과 함수형을 조화롭게 사용할 수 있어요.
 
함수형 스타일을 익히면 코드가 더 간결하고 예측 가능해지고, 재사용성과 테스트 가능성도 높아집니다!