함수형 프로그래밍이 게임 개발에서 유용한 곳은 상태를 없애는 곳이 아니라 상태 변화를 분리하는 곳이다

함수형 프로그래밍을 이야기하면 자주 나오는 오해가 있다. “변수가 없으니 게임처럼 상태가 많은 프로그램에는 안 맞지 않나?”라는 반응이다. 하지만 실제 핵심은 상태를 부정하는 데 있지 않다. 더 정확히는 상태와 상태 변화를 어떻게 다룰지 분리하는 태도에 가깝다.
그래서 함수형 프로그래밍이 게임 개발에 주는 도움도, 엔진 전체를 순수 함수로 바꾸는 데 있지 않다. 규칙 계산, 상태 전이, 메시지 처리처럼 복잡한 변화를 다뤄야 하는 구간을 더 예측 가능하게 만드는 데 있다.
불변성은 “상태가 없다”가 아니라 “함부로 바뀌지 않는다”에 가깝다
Clojure의 공식 문서는 컬렉션 자료구조가 immutable and persistent, 즉 불변이고 이전 버전을 유지하는 구조라고 설명한다. Microsoft의 C# records 문서도 레코드가 주로 불변 데이터 모델을 지원하기 위해 의도되었다고 설명한다.
이 관점이 게임 코드에서 유용한 이유는 분명하다.
- 현재 상태와 다음 상태를 분리해서 볼 수 있다.
- 어떤 함수가 무엇을 바꿨는지 추적하기 쉬워진다.
- 이전 상태를 비교하거나 되돌리는 작업이 쉬워진다.
즉 불변성은 상태를 없애는 기술이 아니라, 상태 변경의 책임을 더 또렷하게 보이게 하는 기술이다.
순수 함수 관점은 규칙 계산을 테스트하기 쉽게 만든다
게임에는 “입력을 받아 결과를 계산”하는 규칙이 많다.
- 피해량 계산
- 아이템 효과 적용
- 전투 결과 판정
- 턴 종료 시 자원 정산
이런 부분은 외부 IO나 전역 상태에 기대지 않고, 입력을 받아 결과만 돌려주는 함수로 분리하기 좋다. 그러면 테스트가 쉬워진다. 같은 입력에는 같은 결과가 나와야 하므로 버그를 좁혀 가기도 편하다.
즉 함수형 사고가 특히 잘 맞는 곳은 게임 세계의 규칙을 계산하는 레이어다.
동시성에서는 “공유 가변 상태를 줄인다”는 발상이 특히 강하다
Erlang의 공식 문서는 언어 자체를 동시성 프로그래밍과 함께 소개한다. 함수형 언어 전반이 공유 가변 상태를 줄이는 방향을 강조하는 이유도 여기 있다. 여러 작업이 동시에 돌 때, 모두가 같은 값을 제멋대로 바꾸는 구조는 버그를 만들기 쉽다.
게임 서버나 백엔드에서 이 관점이 유용한 이유는 명확하다.
- 플레이어 명령을 이벤트로 받아 처리한다.
- 현재 상태를 읽고 다음 상태를 계산한다.
- 결과를 저장하거나 방송하는 부작용은 마지막 단계로 미룬다.
이렇게 나누면 락과 경쟁 상태를 완전히 없애지 못하더라도, 적어도 어디에서 문제가 생기는지 훨씬 분명해진다.
게임 코드 전체를 함수형으로 만들 필요는 없다
여기서 조심해야 할 점도 있다. 렌더링, 입력 처리, 파일 IO, 네트워크 송수신처럼 게임 엔진 바깥과 맞닿는 부분은 본질적으로 부작용이 있다. 이런 곳까지 억지로 순수하게 만들려 하면 오히려 코드가 불편해질 수 있다.
그래서 현실적인 적용은 보통 이렇게 나뉜다.
- 순수하게 만들기 좋은 부분: 규칙 계산, 상태 전이, 데이터 변환
- 효과를 분리해야 하는 부분: 저장, 출력, 렌더링, 네트워크
즉 함수형 프로그래밍은 전체 종교가 아니라, 어디를 더 순수하게 유지할 것인가를 고르는 설계 감각으로 쓰는 편이 낫다.
핵심 정리
함수형 프로그래밍이 게임 개발에서 유용한 이유는 상태를 완전히 없애기 때문이 아니다. 불변 데이터와 순수 함수 관점을 이용해, 상태 변화가 많은 게임 코드의 일부를 더 예측 가능하고 테스트하기 쉽게 만들기 때문이다.
특히 규칙 계산, 상태 전이, 서버 메시지 처리 같은 영역에서는 이 관점이 강하다. 반대로 렌더링과 IO까지 억지로 순수하게 만들 필요는 없다. 결국 중요한 것은 함수형이라는 이름보다, 상태와 부작용을 어디서 어떻게 분리할 것인가다.