8장, 폴리글랏과 폴리패러다임

2022.02.22

함수형 프로그래밍 패러다임은 문제와 그것을 푸는 데 사용되는 도구에 관한 사고의 틀이라고 할 수 있다. 많은 현대 언어들은 폴리패러다임(혹은 멀티패러다임)이다. 이들은 객체지향, 메타프로그래밍, 함수형, 절차형 등 여러가지 패러다임을 지원한다.

8.1 함수형과 메타프로그래밍의 결합

그루비에서 ExpandoMetaClass는 기존의 클래스(언어가 제공하는 기본 클래스를 포함)에 메서드를 덧붙일 수 있게 해준다.

Class IntegerClassifierTest {static {
        Integer.metaClass.isPerfect = {->
            NumberClassifier.isPerfect(delegate)
        }
        Integer.metaClass.isAbundant = {->
            NumberClassifier.isAbundant(delegate)
        }
    }
}

기존 클래스에 메서드를 더하는 행위 자체는, 호출되는 코드가 함수형이라도 특별히 ‘함수형’이라고 부르기는 어렵다. 원활하게 메서드를 덧붙일 수 있는 기능은 함수형 자바와 같이 함수형 기능을 많이 더해주는 타사 라이브러리와의 통합 사용을 쉽게 해준다.

8.2 메타프로그래밍을 통한 자료형의 매핑

그루비는 자바의 변종이므로 함수형 자바 같은 타사 라이브러리를 불러들이는 것은 간단하다. 자료형들 사이에 메타프로그래밍 매핑을 가미하면 이런 라이브러리들을 더 깊이 녹아들게 할 수 있다.

static {
  Stream.metaClass.filter = { c -> delegate.filter c as fj.F) }
  Stream.metaClass.getAt = { n -> delegate.index(n) }
  Stream.metaClass.getAt = { Range r -> r.collect { delegate.index(it) } }
}

메타프로그래밍을 사용하여 함수형 자바 클래스를 컬렉션으로 매핑하기

블록의 몸체는 Streamfilter() 메서드를 호출하여 그루비의 클로저를 함수형 자바의 fj.F 클래스에 매핑한다.

h = [hasNext: { h.i > 0 }, next: {h.i--}]
h.i = 10
def pseudoIterator = h as Iterator

while (pseudoIterator.hasNext())
  print pseudoIterator.next() + (pseudoIterator.hasNext() ? ", " : "\n")
// 10, 9, 8, 7, 6, 5, 4, 3, 2, 1

그루비의 as 연산자를 통해 맵으로 인터페이스 구현하기

8.3 멀티패러다임 언어의 결과가

멀티패러다임 언어는 개발자가 각 패러다임을 적재적소에 사용할 수 있다는 엄청난 이점이 있다.

이점이 많긴 하지만, 개발자들이 큰 프로젝트에 임할 때는 멀티패러다임 언어를 조심해서 사용해야 한다. 언어가 다양한 추상화와 철학을 반영하기 때문에 작은 개발자 그룹이 서로 전혀 다른 라이브러리를 만들 수 있다.

각 패러다임은 근본적으로 다른 각도에서 문제 해결에 접근한다. 객체지향 언어에서는 코드 재사용이 구조 중심이지만 함수형 언어에서는 합성고계함수 중심이다.

한 가지 해법이 있다. 모든 개발자는 같은 목표를 향해 일할 수 있어야 한다는 엔지니어링 철칙에 따른 것이다. 소비자 주도 계약 같은 기법을 사용하면, 팀 간의 실행 가능한 계약을 테스트 형태로 만들 수 있다.

8.4 문맥 대 합성

함수형 사고는 프로젝트에 사용하는 언어에만 적용되는 것이 아니고, 도구 디자인에도 영향을 준다.
플러그인 기반 아키텍처는 문맥에 의한 추상화의 좋은 예이다. 플러그인 기반 아키텍처의 API는 개발자들이 상속받을 수 있거나 기존의 메서드를 사용하여 불러올 수 있는 많은 자료구조와 유용한 문맥을 제공한다. 하지만 이런 API를 사용하기 위해서는 개발자가 문맥이 무엇을 제공하는지를 깊이 이해해야 한다.

합성 위주의 시스템은 서로 연결할 수 있는 세밀한 부분들로 이루어진다. 유닉스 셸에서 서로 다른 기능들을 연결하여 새로운 기능을 만드는 것이 이런 추상화의 대표적인 예이다.

합성 위주의 도구가 문맥 위주의 도구보다 시간, 복잡성, 유용성 등에서 스케일하기 더 쉽다는 것은 경험으로 알 수 있다.

8.5 함수형 피라미드

정적 타이핑은 변수나 함수의 자료형을 사용 전에 확정해야 함을 의미하고, 동적 타이핑은 이것을 미룰 수 있게 함을 의미한다.
타이핑은 가장 중요한 형질인 함수형이냐 명령형이냐에서 주의를 돌리게 하는 레드 헤링일 뿐이다.
중요한 일을 하는 주요 API들이 불변성을 전제로 하면 모든 코드가 아주 간단해진다. 최종 결과로는 중심부의 안정도가 보장된다.

함수형 중심 위에 명령형 언어를 사용하여 워크플로, 비지니스 규칙, 사용자 인터페이스와 같이 개발자 생산성이 최우선인 부분들을 만든다.

과거에는 다양한 언어를 사용하여 명령형으로 설계하는 것이, 통례였다.
함수형 스타일로 갈아타는 것은 단지 새로운 문법을 배우는 것 이상의 큰 전환이지만, 아주 이롭고 중대한 효과를 볼 수 있을 것이다.