본문 바로가기

Development

스크랩 | 함수 프로그래밍이 주목받는 세 가지 이유

최근 들어서 함수 프로그래밍이 새롭게 주목을 받고 있는 이유는 세 가지가 있다. 첫 번째는 멀티코어 CPU를 장착한 컴퓨터가 대세가 되면서 멀티쓰레딩을 지원하는 소프트웨어가 필요하게 되었다는 점이다.

무어의 법칙에 따르면 컴퓨터에서 사용하는 반도체 회로 성능은 대략 18개월마다 2배로 빨라진다. 2000년대 중반까지만 해도 이러한 무어의 법칙은 어김없이 관철되었다. 이것은 곧 시간만 흐르면 (프로그래머가 아무런 노력을 기울이지 않아도) 모든 소프트웨어 성능이 저절로 두 배로 향상되었다는 사실을 뜻한다. 그렇지만 무어의 법칙은 컴퓨터 칩의 속도가 결코 빛보다 빨라질 수 없다는 사실에 대해서는 아무런 말도 하지 않았다.

물리적인 한계에 부딪힌 CPU 회사들은 하나의 칩이 더 빠른 속도를 갖도록 만드는 수직적 전략을 포기하고, 그 대신 여러 개의 칩이 병렬적으로 동작을 하도록 만드는 수평적 전략을 채택했다. 멀티코어 CPU가 등장하게 된 배경이다. 하나의 CPU가 여러 개의 어플리케이션을 실행하던 환경에서 하나의 어플리케이션이 여러 개의 CPU를 이용하는 환경으로 바뀐 것이다.

이전 환경에서 “멀티쓰레딩” 코드는 여러 개의 쓰레드가 하나의 CPU를 가장 효율적인 방식으로 공유하도록 만드는데 초점을 기울였지만, 멀티코어 환경에서 “멀티쓰레드” 코드는 이제 어플리케이션이 동작하는 동안 놀고 있는 CPU가 없도록 만드는데 초점을 기울인다. CPU 성능이 무어의 법칙을 따라 수직적으로 향상되던 시절에는 소프트웨어 성능이 하드웨어 성능 개선과 더불어 향상되었지만, CPU 성능이 수평적으로 향상되는 시절에는 소프트웨어가 멀티코어를 활용하는 동시성 프로그래밍을 적극적으로 지원하지 않으면 성능이 향상되지 않는다. 어브 써터(Herb Sutter)같은 사람은 이러한 현상을 두고 “공짜 점심은 끝났다”라는 유명한 말을 남기기도 했다.

동시성 코드를 작성하는 것은 어렵다. 프로그래밍 실력이 아무리 뛰어난 사람이라고 해도 정확성을 100% 보장하는 동시성 코드를 작성하는 것은 불가능하다. 브라이언 괴츠의 Java Concurrency in Practice는 현대의 프로그래머들에게 동시성 코드를 작성하는 것이 왜 어려운지, 어느 정도로 어려운지, 어째서 잠금(lock)이나 세마포(semaphore) 같은 동시성 프로그래밍의 어셈블리 언어를 사용하는 상황을 피해야 하는지 잘 보여주었다.

자바나 C# 같은 명령형(imperative), 객체 지향적 언어를 이용해서 동시성 코드를 작성하는 것이 지극히 어려운 이유는 여러 가지가 있는데, 이러한 언어에서는 객체 상태나 데이터 값이(프로그래머가 특별한 노력을 기울여서 일부러 막지 않는 한) 기본적으로 변경 가능(mutable)하다는 사실이 가장 결정적인 이유다. 객체 상태나 데이터 값은 여러 쓰레드가 공유하는 경우가 많다. 데이터가 공유된다는 사실 자체는 별로 문제가 아니다. 하지만 공유되는 데이터가 변경 가능하면 비극이 시작된다. 데이터의 공유와 변경 가능성(mutabiliy)은 죽음의 칵테일이다.

함수 프로그래밍이 새롭게 주목을 받는 이유는 바로 이 지점에 있다. 함수 프로그래밍에서는 모든 데이터가 기본적으로 변수가 아니라 상수다. 즉, 값이 변경 불가능(immutable)하다. 값이 변경되지 않는 상수는 아무리 많은 쓰레드가 동시에 접근하더라도 동시성과 관련된 문제를 야기하지 않는다. 그들은 잠금(lock)을 통해서 보호될 필요도 없고, CPU의 레지스터에 저장되는 캐시 값과 관련된 가시성(visibility) 문제를 일으키지도 않는다. 함수 프로그래밍은 멀티코어 CPU 환경에서 발생하는 동시성 프로그래밍과 관련된 문제를 예컨대 객체지향 언어보다 뛰어난 멀티쓰레딩 구조물을 통해서 해결하는 것이 아니라, 그러한 구조물의 필요성 자체를 제거하는 방식으로 해결한다는 점에서 (오래된)혁명이다.

최근에 와서 함수 프로그래밍이 주목을 받는 이유의 두 번째는 코드의 간결함이다. 객체지향 언어를 오랫동안 사용해온 프로그래머라면 전략패턴(strategy pattern)이나 방문자 패턴(visitor pattern)과 같은 종류의 디자인 패턴에 친숙할 것이다. 이러한 패턴은 유용하지만, 함수 프로그래밍의 입장에서 보면 우격다짐에 가깝다.

반드시 필요한 논리와 추상을 추려내서 우아하게 표현하는 것이 아니라, 패턴 자체를 위한 인터페이스를 정의하고, 인터페이스를 구현하는 내용을 작성하고, 인터페이스에 정의된 메쏘드를 미리 정해진 방식에 따라서 호출하는 과정에는 본질적이지 않은 부수적이고 장식적인 코드가 너무 많기 때문이다.(앤더스 하일스버그 같은 사람은 비본질적인 코드를 세레모니(ceremony)라고 표현한다. 세레모니는 적을수록 좋다.)

함수 프로그래밍에서 사용하는 중요한 개념인 커리(curry), 부분 어플리케이션(partial application), 모나드(monad)와 같은 기법은 지극히 간결하고 우아한 함수의 구성(composition)을 가능하게 해준다. 이러한 개념에 대해서는 나중에 더 자세히 설명하도록 하겠다. 자바에 비해서 한 발 앞서 람다(lambda)나 클로저(closure)같은 구조물을 지원한 C#은 (자바에 비해서)함수 프로그래밍 언어의 특징을 많이 가지고 있다.

도메인 특정 언어(DSL: Domain Specific Language)로 분류되는 LINQ는 C# 내부에 존재하는 일종의 함수 프로그래밍 언어다. 프로그래머로 하여금 “어떻게”가 아니라 “무엇”에 집중하게 만들어 준다는 점에서 LINQ는 그 자체로 함수 언어로 봐도 무방하다. 이런 맥락에서 보자면 프로그래머들이 흔히 사용하는 SQL 언어도 함수 언어다. (데이터베이스 서버에 SQL 질의문을 보낼 때, 그 구문이 실행되는 동안 발생할 지도 모르는 멀티쓰레딩 문제를 고민한 적이 있는가? 아마 없을 것이다. “어떻게”는 데이터베이스 서버가 알아서 할 일이고 프로그래머는 “무엇”에만 집중할 수 있기 때문이다.)

함수 프로그래밍이 주목을 받는 세 번째 이유는 자바와 C# 같은 기존의 언어가 발전모드에서 관리모드로 접어들면서 프로그래밍 언어와 관련한 새로운 패러다임이 요구되는 현실과 관련이 있다. 자바의 JVM이나 C#의 .NET CLR은 특정 언어에 국한되지 않는 일종의 플랫폼 역할을 하기 때문에 이러한 플랫폼 위에서 다양한 언어적 실험이 이루어지고 있다는 현실과도 무관하지 않다.

루비나 파이선 같은 동적 언어에서 스칼라나 F#과 같은 함수 언어에 이르기까지 매우 다양한 스펙트럼의 언어가 JVM과 .NET 플랫폼을 대상으로 실험되고 있다. JVM에서 동작하는 언어가 자바만 있는 것으로 알고 있는 사람이라면 당장 위키피디아에서 List of JVM languages 항목을 검색해보기 바란다. JVM 위에서 얼마나 많은 언어가 동작하는지 알면 깜짝 놀랄 것이다. 함수 프로그래밍 패러다임은 객체지향 패러다임의 뒤를 이을 새로운 패러다임을 발견하기 위한 전반적인 실험과 암중모색의 와중에 하나의 강력한 대안으로 주목을 받고 있다.

[관련글]프로그래밍 세계의 새로운 버즈워드-함수 프로그래밍
요즘 컴퓨터 프로그래밍의 세계에서는 단연 ‘함수 프로그래밍(functional programming)’이 주목을 받고 있다. 함수 프로그래밍은 프로그래밍 세계의 ‘버즈워드’인 셈이다. 함수 프로그래밍은 새로운 패러다임이 아니다. 함수 프로그래밍의 역사를 짚으려면 거의 1950년대로까지 거슬러 올라가야 할 정도다. 함수 프로그래밍 패러다임은 80년대 무렵에 C 언어의 절차적(imperative) 패러다임의 뒤를 잇는 차기 패러다임의 자리를 놓고 객체지향(object-oriented)패러다임과 자웅을 겨루었다.

 

출처 : http://techit.kr/6472