ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 함수형 프로그래밍 개론
    Languages/JavaScript 2024. 2. 4. 20:06

    처음 실무에서 개발을 할 때 사수로부터 중요성을 그리고 지금까지도 팀원들과 이야기를 계속하는 함수형 프로그래밍은 개발을 하는 데 있어 베이스가 되고 늘 중요성을 이야기합니다. 프로그래밍 패러다임 중 하나이며 선언형 프로그래밍 중 하나인 함수형 프로그래밍에 대해 설명하고자 합니다.

     

    프로그래밍 패러다임(programming paradigm)

    프로그래밍 패러다임은 개발자에게 프로그래밍의 관점을 갖게 해 주고 결정하는 역할을 합니다. 최근에는 명령형 프로그래밍과 선언형 프로그래밍으로 구분하여 이야기합니다.

     

    명령형 프로그래밍 ⇒ 어떻게 할 것인가? (How)

    프로그래밍의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하며 절차적 프로그래밍(Procedural Programming, PP)과 객체 지향 프로그래밍(Object-Oriented Programming, OOP)이 속해있습니다.

    • 절차적 프로그래밍은 데이터의 처리에 대해 절차적으로 처리하는 방식이며 절차적 프로그래밍 언어로는 C가 있습니다.
    • 객체 지향 프로그래밍은 객체의 관계를 통해 처리하는 방식이며 객체 지향 프로그래밍 언어로는 Java, Python, C# 등이 있습니다.

    선언형 프로그래밍 ⇒ 무엇을 할 것인가? (What)

    프로그램이 어떤 방법으로 해야 하는지를 나타내기보다 무엇과 같은지를 설명하는 경우 선언형이라고 하며 함수형 프로그래밍(Functional Programming)이 속해있습니다.

    • 함수형 프로그래밍은 상태값을 지니지 않는 순수 함수로 구성되며 함수형 프로그래밍 언어로는 스칼라, 클로저 등이 있습니다.

    프로그래밍 패러다임을 검색하면 많이 찾아볼 수 있는 이미지입니다. 해당 이미지만 보면 함수형 프로그래밍이 객체 지향 프로그래밍보다 진화하여 더 나은 것처럼 보이지만 실제로 함수형 프로그래밍 방법론은 객체 지향 프로그래밍 방법론보다 먼저 등장하였고 서로의 방법론이 다른 것이지 어떤 것이 더 낫다고 할 수는 없습니다.

     

    함수형 프로그래밍?

    함수형 프로그래밍은 수학적 개념이자 함수 합성을 기반에 둔 람다 대수 베이스 한 방법론입니다. 하지만 수학적 개념이 짙고 이해하는데 어려움이 많다 보니 사람의 사고방식과 비슷한 객체 지향 프로그래밍이 먼저 각광을 받게 됩니다. 그러다 하드웨어 발전의 한계점으로 단일 코어의 성능 발전보다 코어의 수를 늘리는 방식으로 선회하면서 소프트웨어에서도 동시성 프로그래밍이 떠오르게 됩니다. 기존의 개발 방법론으론 동시성 프로그래밍에서 동시성을 제어하거나 동시성 버그를 잡기에는 많은 어려움이 있었습니다. 이러한 어려움은 데이터가 변화기 때문에 발생하는데 이에 따라 데이터 불변성을 지키는 함수형 프로그래밍이 떠오르게 됩니다. 또한 기존 객체 지향 프로그래밍에서 과도한 추상화로 인해 코드의 복잡성이 올라갔지만 함수형 프로그래밍에선 문제 해결을 위해 순수 함수로 작성하기 때문에 간결하고 읽기 쉬워 유지 보수에도 용이합니다.

     

    그렇다면 함수형 프로그래밍이 무엇인지에 대해서 알아보겠습니다. 함수형 프로그래밍이란 문제 해결을 위해 부수 효과(Side Effect)가 없는 순수 함수(Pure Function)를 작성하여 프로그램을 만드는 것입니다. 부수 효과와 순수 함수가 핵심 키워드인데 이에 대해 더 알아 보겠습니다.

     

    부수 효과(Side Effect)

    함수에는 일반적인 입출력과 보이지 않는 입출력 이 두 가지의 입출력을 가집니다. 흔히 매개변수를 받아 return 하는 함수가 아닌 입력과 출력이 없더라도 무언가 의존성을 가지며 어떠한 동작을 수행하는 함수가 존재하는 데 이를 보이지 않는 입출력을 가지는 함수라고 합니다. 이러한 보이지 않는 입출력을 부수 효과(Side Effect)라고 하며 Side Effect를 가지는 함수는 참조 투명성이 없기 때문에(의존성을 가지기 때문에) 동일 입력에 대한 동일 출력을 보장할 수 없습니다. 그렇기에 Side Effect를 없애기 위해 프로그램 상태의 값을 불변 상태로 만들어 관리합니다. (⇒ 보이지 않는 출력을 Side Effect, 보이지 않는 입력을 Side Cause로 보기도 합니다.)

     

    순수 함수(Pure Function)

    그래서 Side Effect가 없는 함수를 구현하려 하는데 입력이 입력으로 선언되고 출력이 출력으로 선언되는(보이지 않는 입출력이 없는) 함수를 순수 함수(Pure Function)라고 하며 해당 함수를 순수(pure) 하다고 부릅니다. 순수 함수는 함수 자체가 독립적이므로 함수의 실행이 외부에 영향을 미치지 않으며 Side Effect가 없어 Thread의 안정성을 보장받습니다.

     

    함수형 프로그래밍 특징

    함수형 프로그래밍은 다음과 같은 특징을 가지며 각각의 특징을 하나씩 알아보겠습니다.

    • 불변성(Immutable)
    • 1급 객체(First-class Object)
    • 참조 투명성(Referential Transparency)
    • 게으른 평가(Lazy Evaluation)

    불변성(Immutable)

    함수형 프로그래밍에서는 데이터의 변화를 Side Effect로 간주합니다. 그래서 데이터의 변화가 필요할 경우 데이터 불변성을 지키기 위해 원본 데이터를 복사하여 복사본을 가공하여 사용합니다.

    const numArr = [1, 2, 3];
    const convertedNumArr = numArr.map((v) => v * 2);
    
    console.log(numArr); // [1, 2, 3]
    console.log(convertedNumArr); // [ 2, 4, 6 ]
    
    // => 원본 데이터의 변화가 발생하지 않아 불변성을 지킴

     

    1급 객체(First-class Object)

    함수형 프로그래밍에서의 함수는 1급 객체가 됩니다. 1급 객체는 아래와 같은 특징을 가지는 객체를 뜻합니다.

    • 매개변수(Argument)로 전달 할 수 있다.
    • 반환(Return)값이 될 수 있다.
    • 할당의 대상(변수)이 될 수 있다.
    • 비교 연산을 적용할 수 있다.

    참조 투명성(Referential Transparency)

    참조 투명성은 함수 외부에 의존하는 요소가 없고 동일한 인자에 대해 동일한 결과가 나오는 것을 뜻합니다. 해당 내용은 순수 함수의 특징을 말하고 있으며 함수 외부의 영향은 Side Effect이므로 함수 외부에 의존하지 않고 독립적이어야 합니다.

     

    게으른 평가(Lazy Evaluation)

    게으른 평가 또는 지연 평가는 값이 필요한 시점에 계산을 하는 것으로 값이 필요하기 전까지 계산을 하지 않아 불필요한 계산을 줄여 성능을 향상시킵니다.

    function* foo(index) {
      while (true) {
        yield index;
        index++;
      }
    }
    
    const iterator = foo(0);
    
    console.log(iterator.next().value); // 0
    console.log(iterator.next().value); // 1
    
    // => 값이 필요할 때 계산

     

     

    함수형 프로그래밍의 특징을 잘 나타내는 문장을 하나 소개하며 함수형 프로그래밍 특징에 대해 마무리하겠습니다.

    부수 효과(Side Effect)가 없는 순수 함수(Pure Function)를 1급 객체(First Object)로 간주하여 파라미터로 넘기거나 반환값으로 사용하며, 참조 투명성을 지킬 수 있다.

     

    함수형 프로그래밍이란?

    결국 함수형 프로그래밍이란 순수 함수를 작성하여 최대한 보이지 않는 입출력인 부수 효과(Side Effect)를 줄이는 것입니다. 하지만 Side Effect를 완전히 제거할 수는 없습니다. 코드를 작성함에 있어 동작에 초점을 맞추기 때문에 Side Effect는 존재할 수밖에 없습니다. 그래서 개발자들은 최대한 Side Effect를 제거해야 하며 제거할 수 없는 경우 철저한 통제가 필요합니다.

     

    회고

    코드를 구현할 때 Array의 map()와 Object의 assign()을 사용하여 각각 새로운 array와 object를 반환하여 많이 사용하는데 함수형 프로그래밍에서 데이터 불변성을 지키기 위해 사용되는 방식입니다. 이처럼 처음엔 모르고 사용하는 것들도 알고 다시 보면 다르게 보입니다. 개발 공부에 끝이 없음을 또 깨닫습니다.


    참고 자료

    https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98%ED%98%95_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D

    https://brunch.co.kr/@wegra/20

    https://medium.com/@jooyunghan/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-fab4e960d263

    https://mangkyu.tistory.com/111

    https://medium.com/humanscape-tech/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%97%90-%EA%B4%80%ED%95%B4-7f6172599fc

Designed by Tistory.