함수형 프로그래밍에 대한 개념 잡기

신호승·2020년 10월 11일
2
post-thumbnail

본 글은 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()) // function 자체를 인자로 받아 다시 atom 안의 변수 값에 someValue를 다시 반영

    예시: 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하게 만들어야 하니 처음 시도하게 되면 이런 규칙들이 족쇄처럼 느껴질 것이다.
  • 하지만 조금 익숙해지면 더욱 가독성이 좋고, 디펜던시가 최소화 되기 때문에 생산성의 향상을 경험할 수 있을 것이다.
  • 출처 : https://www.youtube.com/watch?v=0if71HOyVjY

    profile
    Front-End developer

    0개의 댓글