본 글은 2018년 GOTO conference에서 Russ Olsen이 발표한 'Functional Programming in 40 Minutes' 의 강연 내용을 제가 이해한 내용을 바탕으로 정리한 것입니다.
객체지향과 비교하여 강의가 진행되기 때문에, 객체지향에 대한 이해가 조금 있으면 이 강의를 듣는데 도움이 됩니다.
객체지향 프로그래밍의 한계점
객체 지향 프로그래밍은 현재 가장 유명한 프로그래밍 패러다임이다
우리가 세상 사물을 보는 방식 그대로 프로그래밍 하는 방식이다(클래스로부터 인스턴스를 찍어내고 각 인스턴스에는 속성과 메서드가 존재하고, 인터페이스가 존재하는걸 보면 그렇다)
하지만 아무리 잘 짜더라도, 설계의 변경과 유지 보수를 하다 보면 필연적으로 이상적이지 않은 디펜던시가 생기기 마련이고, 이것이 추가 기능의 삽입이나 디버그를 굉장히 힘들게 한다.
=> 개인적인 생각으로는, 각각의 인스턴스가 속성을 가지고 있기 때문에 이 상태에 따라 같은 메서드나 로직이 수행되더라도 결과가 달라져서 그런 것 같다.
=> 근본적으로, 시간에 따라 변하는 속성을 제대로 파악하지 못하는 지경이 되는 것이 문제같은데, 이걸 해결할 방법이 마땅치 않아 보인다.
대체제가 있을까?
많은 부분을 대체할 필요는 없다. 객체지향을 이루는 부분들만 다른 구성 요소로 바꾸면 된다
클래스 / 인터페이스 / 메서드를 => 어떤 다른 요소?
함수형 프로그래밍을 생각해 본다면 어떨까?
순수 함수 / 불변성 자료 구조 / 사이드 이펙트 브릿지 가 해답이 될 수 있다.
=> 객체지향을 이루는 요소들 대신, 함수형 구성 요소인 순수 함수 / 불변성 자료 구조 / 사이드 이펙트 브릿지를 활용하면 더 좋은 프로그래밍이 가능할 수 있다.
함수형 구성 요소
1. 순수 함수
같은 입력에 대해 항상 똑같이 출력함
외부에 영향을 주거나 받지 않음
사이드 이펙트
함수를 순수하지 않게 만드는 모든 효과
순수 함수가 왜 중요한가?
어디에서 호출이 되든, 어떤 시점에서 호출이 되든 입력값이 정상이면 출력값도 정상이기 때문
순수 함수로만 로직을 구현한다면 로직 덩어리 전체가 순수하므로 유지 보수나 기능의 추가가 매우 용이함
=> 디펀덴시가 최소화됨
2. 불변성(Immutable) 자료 구조
순수 함수를 사용해서 로직을 구성할 경우, 함수 인자나 외부 변수를 직접 바꾸면 안 되며 항상 새로운 변수를 만들어서 값을 전달해야 함.
=> 왜 그럴까? 불변하지 않으면 사이드 이펙트가 발생하는 것과 동일함. => 따라서 순수 함수를 사용하는 이점이 의미가 없어짐
이렇게 되면 문제가 한 가지 있는데, 같은 값을 매번 복사해야 함
만약 엄청 큰 배열을 복사해야 한다면 그 오버헤드는 어마어마함.
이럴 경우를 방지하기 위한 persistent data structure가 존재함. 변하는 요소의 node만 부분적으로 복사함
3. 사이드 이펙트 브릿지 - closure(클로져) 방식
하지만, 궁극적으로 우리가 원하는 것은 사이드 이펙트임
쉽게 말해서, 서버에 데이터를 요청하거나, 데이터베이스를 업데이트하는 등의 실질적인 생산 활동 자체가 사이드 이펙트임
따라서, 필요한 부분에만 사이드 이펙트를 유발할 수 있도록 순수 함수 로직 안에서 그 경로를 뚫어주어야 함
강연자는 이것을 'messy outside world' 와 'lovely functional world'의 브릿지라고 표현함
예시: Atoms
A container for mutable state
함수를 atom에 던지면 그 함수 결과 값으로 변수값을 다시 설정
function funcA() {
... 연산 후
return someValue
}
Atom(funcA())
예시: atom은 mutable variable를 그냥 하나를 두는 것과 무엇이 다른가?
여러 개의 쓰레드가 동시에 mutable variable 하나를 변경하려고 시도하면 업데이트가 누락되는 등의 문제가 생긴다
Atom은 상태값을 변경하는 순수함수가 들어오면 그걸 queue에 가지고 있다가, 자체적으로 순서대로 돌려 처리하므로 이런 문제가 없다.
또한 코드 상으로 비교해 봤을 때, mutable variable은 함수 문 내부에서 접근해야 되는 것과 달리,
atom은 순수함수를 인자로 받아 코드 상에서도 철저히 messy outside world와 lovely functional world를 분리시킬 수 있으므로 구조상에서도 큰 이득이다
=> 바닐라 자바스크립트에서는 이런 구조를 만들 수 있을까? 한번 시도해 봐야겠다. 그 후 업데이트 예정
예시: agents/actors
atom과 비슷하게, 순수함수를 인자로 받아 side effect를 수행하는 어떤 장치
특히 웹서버에 요청, 데이터베이스 업데이트, 파일 삭제 및 추가 같은 비동기 작업 같은 경우에 순차적으로 처리할 수 있도록 queue를 가지고 있어서 messy outside world와 lovely functional world를 분리할 수 있는 bridge 역할을 성공적으로 수행한다
=> 이것도 바닐라 자바스크립트에서 만들 수 있을까? 해보고 업데이트 예정
함수형만이 갖는 압도적 장점 => 여러 쓰레드를 활용할 경우
순수함수 + Immutable data structure가 합쳐지면, 적어도 연산 과정에서 이미 있는 data structure를 mutate하여 다른 쓰레드가 엉뚱한 연산 결과를 내뱉는 것을 근본적으로 방지할 수 있다.
따라서 다중 쓰레드 작업에 유리하다.
함수형 프로그래밍을 시도해보자
변수를 모두 immutable 하게 만들고, 함수로 무조건 무언가를 return하게 만들어야 하니 처음 시도하게 되면 이런 규칙들이 족쇄처럼 느껴질 것이다.
하지만 조금 익숙해지면 더욱 가독성이 좋고, 디펜던시가 최소화 되기 때문에 생산성의 향상을 경험할 수 있을 것이다.