[Java] Functional Programming

Jane·2021년 1월 19일
7
post-thumbnail

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

자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임 중 하나이다.

특징

  • 모든 것을 객체로 취급한다.
    클래스 뿐만 아니라 함수도 객체이기 때문에 어떤 함수를 다른 함수의 인수로 전달하고, 결과값으로 함수를 반환하는 것이 가능하다.

    1급 객체(시민)의 조건

    • 변수나 데이터에 할당할 수 있어야 한다.
    • 객체의 인자(parameter)로 넘길 수 있어야 한다.
    • 객체의 return 값으로 반환할 수 있어야 한다.
    위의 기준에 따르면 Java의 1급 시민은 객체이며, 메서드는 1급 시민이 아니다.
    람다식은 메서드가 아닌 함수형 인터페이스를 구현한 익명 클래스의 객체라고 할 수 있다.

    함수형 인터페이스
    람다식을 다루기 위한 인터페이스로, 람다식의 매개변수의 타입, 개수, 반환값과 일치하는 메서드 한 개만 선언되어 있는 인터페이스

  • 변경 가능한 상태를 불변(Immutable) 상태로 만들어 side effect를 제거한다.

    불변성(Immutable) : 가변 변수를 사용하는 대신 심볼의 값이 할당 이후에 변경되지 않는 성질


순수 함수 (Pure function)

수학에서는 '상태'라는 개념이 없기 때문에 모든 함수는 함수 외부에 영향을 받지 않고 독립적으로 존재하는데, 이러한 수학의 함수를 프로그래밍 세계로 가져와 만든 모델이 순수함수이다.

특징

  • 함수 외부의 값이나 객체에 의존적이지 않기 때문에 참조투명성을 가진다.
  • 상태를 변경하지 않기 때문에, 부작용(side-effect)이 없다.

    순수함수의 불변성은 다음과 같은 장점을 갖는다.

    1. 함수 외부의 상태에 접근하여 이미 메모리에 할당되어 있는 값을 변경하지 않기 때문에 예측하지 못한 상태의 변경을 방지할 수 있다.
    2. 참조에 의한 호출을 사용하는 자료형들의 상태 변화를 쉽게 감지할 수 있기 때문에 상태의 변경을 추적하기 쉽다.
  • 함수의 실행이 외부에 영향을 미치지 않기 때문에 스레드 안전(Thread-safe)하고 병렬적인 계산이 가능하다.

    데이터가 불변 객체에 저장되어 있다면 복수의 스레드에서 특정한 스레드의 데이터가 변경될 걱정 없이 데이터에 접근하는 것이 가능하다.


객체지향 프로그래밍 vs. 함수형 프로그래밍 (OOP vs. FP)

※ 이 부분 이후로는 주관적인 의견이 많이 포함되어 있으며, 프로그래밍 새내기의 관점에서 작성된 글임을 기억해주시면 감사하겠습니다. 코멘트 또한 환영합니다💞

객체지향 프로그래밍은 imperative programming(프로그래밍의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하는 프로그래밍 패러다임)으로 문제를 작은 객체 단위로 나누고, 여러 객체들을 조합해서 큰 문제를 해결하는 상향식(Bottom-up) 해결법을 사용한다. 따라서 객체지향 프로그래밍을 사용하면 복잡하고 규모가 큰 소프트웨어도 개발 및 관리하기 용이하다는 장점이 있다.

한편, 함수형 프로그래밍은 declarative programming(프로그램에서 실행되는 각 구문, 명령어나 함수가 호출되는 순서를 설명하지 않고 computation logic을 표현하는 프로그래밍 패러다임)으로 문제를 작은 함수 단위로 나오고, 목표중심적으로 프로그램을 표현한다.

다음은 함수형 프로그래밍과 비교했을 때 객체지향 프로그래밍이 갖고있는 단점으로 언급되는 내용들인데, 관점에 따라 단점이 아닌 장점으로 작용할 수도 있겠다는 생각이 들었다.

1. 함수의 비일관성
→ 객체지향 프로그램의 함수(메서드)는 동일한 입력에 대해서 다른 결과를 반환(Return)하는 경우가 있으며, 이는 실제 테스트 케이스 작성 및 디버깅에 어려움을 주기도 한다.

동일한 입력에 따라 다른 결과를 반환하는 메서드가 존재한다면, 동작 결과에 대한 예측과 테스트가 어려워진다는 점에 대해서는 동의한다. 그러나 동일한 입력에 대해서도 overriding을 통해 객체마다 다른 결과를 낼 수 있도록 하는 것이 다형성이며, 이는 객체지향의 장점이기도 하다.

예를들어 삼각형과 사각형의 넓이를 구하는 메서드를 정의했다고 하자. 동일한 입력에 대해 항상 동일한 결과를 반환하는 순수함수의 경우, 높이와 밑변의 길이가 주어졌을 때 각각 넓이를 구하는 함수를 따로 정의해야 하며 사용자는 각 함수를 따로 호출해야 할 것이다. 그러나 객체지향 프로그래밍에서는 사용자가 삼각형인지 사각형인지를 신경쓸 필요 없이 "다각형의 넓이를 구하라"라는 메시지만 전달한다면, 삼각형과 사각형 객체 각각에 override되어 있는 getArea()라는 메서드를 호출되어 넓이를 반환한다.

2. 객체 간 의존성 증가
→ 객체 간 상호작용을 위해 함수가 다른 객체의 함수를 호출하기 때문에 함수의 재사용성(Reusability)이 떨어지며 프로그램의 복잡도가 증가한다.
3. 객체 내 상태 변화 제어의 어려움
→ 외부 경로를 통해 객체 내 함수가 호출되는 경우, 어느 시점에 어떤 외부경로를 통해 상태가 변경되었는지 추적하기 어렵다.

객체 간의 의존성 증가와 객체 내 상태변화 제어의 어려움 또한 객체지향의 절대적인 단점이라기 보다는 객체지향의 가장 큰 특성인 객체 간의 소통과 협력으로 인해 발생하는 결과라고 이해할 수 있다.

따라서 객체지향 프로그래밍과 함수지향 프로그래밍은 하나가 더 우수하거나 열등한 것이 아니라, 더 적합한 상황만이 존재하며 상호보완적이라는 생각이 든다.

Q. 생각해 볼 거리
클린코드를 보면 클래스 또는 메서드가 한가지 일만 처리할 것을 권장하고 있는데 이는 함수형 프로그래밍의 장점을 가져와 객체지향 프로그래밍의 단점을 개선하려고 하는 것일까? 객체지향 프로그래밍만 공부했을 때는 몰랐었는데, 함수형 프로그래밍의 개념을 접하고 나니 OOP의 장점을 취하면서도 코드의 재사용성을 높이고 객체 간 의존성을 줄이기 위해 FP의 개념을 일부 사용하고 있는 게 아닌가 하는 생각이 든다.


Source

4개의 댓글

comment-user-thumbnail
2021년 1월 20일

내용이 좋아보여요!! 일단 하트누르고 나중에 한번 읽어보겠습니다. ㅎㅎ

1개의 답글
comment-user-thumbnail
2021년 1월 20일

매번 느끼지만 글솜씨가 장난 아니시네요. 공부 많이 됐습니다. ㅎㅎ
그런데 Jane 잠은 주무시는거 맞죠..?😦

1개의 답글