클로저 소개 - 제6회 리스프 세미나 발표

TL;DR

  • 리스프 세미나에서 클로저 소개 발표했음
  • 클로저 겁나 멋지고 신나는 언어임
  • 클로저를 배우고 나면, 다른 언어를 쓰더라도 간지 쩌는 코드 나옴
  • 배워볼지 말지, 이하 읽어보시고 판단합서~!
어제 11월 11일 토요일, 강남역 근처 NAVER D2 Startup Factory에서 제 6회 리스프/클로저 세미나가 열렸습니다. 감사하게도, 간단히 클로저 프로그래밍 언어를 소개를 하는 발표 기회를 얻어서, 처음으로 참석하면서 발표도 할 수 있었습니다.
여러모로 아쉬움이 많이 남는 발표였지만, 그래도 자료를 공유합니다. 당시 발표는 준비했던 스크립트와 꽤 다르게 진행했지만, 여기 공유하는 자료는 미리 준비했던 스크립트를 다시 정리해서 올린다는 점 말씀드립니다. 아마 발표를 들으셨던 분들은, “그때 이런 말을 했었어?!”라고 의아해하실지도 모르겠네요. 사실상 슬라이드만 같지, 다른 내용인 느낌적 사실?! ;-)

안녕하세요. 제 이름은 김대현이고 미디엄에 @hatemogi라는 아이디로 가끔 글을 올리고 있습니다. 예전에 회사 다닐 때는 자바, C, 루비 등으로 웹서비스 백엔드 개발을 하다가, 최근 몇 년은 프리랜서로 지내고 있고, 운 좋게 클로저로도 일하고 있습니다. 오늘 여섯 번째 리스프 세미나라고 들었는데요, 저도 클로저나 리스프를 아직 잘 모르는 입장이라 많이 부족하지만 따뜻한 관심 부탁드리겠습니다.

발표는 세 부분으로 나눠서, 먼저 클로저 특징을 설명하고, 그다음 클로저 환경에서 개발 툴들을 몇 가지 안내해드리겠습니다. 그리고 마지막으로는 실제 클로저로 작성한 예제 코드를 따라가면서 기초 문법을 설명드리려 합니다. 준비해 온 예제 부분은 시간 내에 다 설명하지는 못할 것 같고, 되는 데까지 해보겠습니다.

Part 1. 먼저 클로저 언어의 특징을 소개합니다.

현존 프로그래밍 언어 중 가장 오래된 언어가 포트란과 리스프라고 하죠? 리스프는 약 60년 전에 존 매카시라는 컴퓨터 과학자가 만든 프로그래밍 언어인데, 그 후손으로 커먼 리스프, 스킴, 라켓 등으로 이어집니다. 클로저는 2007년에 리치 히키라는 실용 프로그래머가 현대적으로 만든 리스프 스타일 언어입니다. 처음 공개한 지 10년쯤 된 신생 언어입니다.

클로저는 동적 타입의 컴파일 언어이고, 함수형 프로그래밍을 지향하며, 자바 가상 기계 JVM 위에서 운용됩니다. JVM 말고도, 닷넷 환경을 위한 ClojureCLR이 있기는 한데 많이 쓰이는지는 않는 것 같고, JavaScript로 컴파일되는 클로저스크립트의 경우는 브라우저 환경이나 node.js 환경에서 꽤 쓰이고, 오늘 세미나 중 관련 발표도 있는 걸로 알고 있습니다. 저는 JVM 중심으로만 발표합니다.

클로저 매력은 다양하겠지만, 우선 클로저로 작성하는 코드가 아주 간결하고 우아하면서 많은 일을 할 수 있다는 점을 꼽겠습니다. 그리고, 자바 가상 기계에서 실행되면서, 자바 클래스나 객체에 직접적으로 접근하기 아주 쉬워서, 결국 자바가 쓰이는 환경 어디나 그대로 유용하게 활용할 수 있는 강점이 있습니다. 리스프의 특징을 이어받아 확장성도 매우 뛰어나고, 언어 전반에 함수형 프로그래밍과 동시성 처리가 기본으로 깔려있다는 점도 장점으로 매력적입니다.

클로저의 많은 부분이, 리스프의 특징을 이어받았기 때문에 강점으로 드러나는데요, 리스프와 마찬가지로 언어 자체의 기본 데이터로 코드를 표현한다는 점과 레플 중심으로 처리한다는 점, 리스트를 비롯한 각종 시퀀스를 다루는 기능이 매우 강력하다는 강점이 있습니다. 그리고 리스프의 독특한 매크로 기능으로 이용자가 문법을 자유롭게 추가할 수 있다는 특징도 있습니다.

거의 모든 프로그래밍 언어가 레플을 지원하지만, 레플의 원조는 리스프입니다. read, eval, print, loop가 리스프의 실재 함수명인데요, 원조의 후예이니만큼 레플과 아주 밀접하게 연동해서 유연하게 개발합니다.

그리고, 클로저는 컴파일 방식의 언어이라 결과 코드의 성능이 빼어나면서도, 인터프리터 방식의 언어처럼 유연한 특징들이 있습니다. 코드를 실행 시점에 바로바로 동적으로 컴파일해서 실행하는 흥미로운 방식입니다.

이 동적인 개발 환경을 좀 더 설명하기에 앞서, 아주 기본적인 문법 사항 몇 가지 설명드리겠습니다.

클로저에서는 이런 타입의 값들을 기본으로 다룹니다. 정수는 보통의 64비트 Long 정수형이고, 실수는 더블, 그리고 64비트 범위를 넘어가는 매우 큰 실수나 정수를 다루는 타입도 있습니다. 또 특이하게 기본 단순 값에 분수 타입도 있어서, 정확도 손실 없이 분수 계산을 할 수 있습니다. 문자열은 자바의 java.lang.String을 별도 래핑 없이 그대로 쓰고, 문자도 자바의 Character라서 유니코드 문자를 그대로 다룹니다. 심볼은 어떤 대상을 가리키기 위한 이름으로 활용되는데, 보통 언어의 지시자 역할을 한다고 보면 크게 틀리지 않을 것 같습니다. 키워드는 콜론으로 시작하는 이름인데, 키워드는 평가해도 그 자신이 나오는 특별한 값인데요, 몇몇 상황에 아주 유용하게 사용되는 경우가 있어서 눈여겨볼 필요가 있습니다. 불린은 true나 false로 어떤 논리식을 다루기 위한 타입이고, nil은 값이 없다는 것을 나타내는 자바의 null입니다. 그리고 정규식의 경우에도 기본 단순값으로 다룰 수 있습니다.

다음으로, 단순값들을 담고 있을 수 있는 기본 자료 구조들을 소개합니다. 먼저 단일 연결 리스트로 새로운 값들이 앞에 추가하기 좋은 리스트가 있고, 배열처럼 특정 인덱스에 콕 집어 접근하거나, 뒤에 새 값을 추가하기 효율적인 벡터가 있습니다. 리스트는 괄호로 감싸고, 벡터는 대괄호로 감싸서 표현합니다. 맵은 여타 언어의 딕셔너리나 해쉬맵이라고 부르는 자료형과 비슷합니다. 어떤 키와 값들을 쌍으로 다루는 자료구조이며, 키나 값 모두에 어떤 타입의 값이 있어도 됩니다. 앞의 맵은 키워드를 키값으로 사용했고, 오른쪽의 맵은 정수를 키값으로 사용했습니다. 값들을 중복되지 않게 보관하는 집합도 기본 자료 구조에 포함됩니다. 그리고 여기 나온 리스트, 벡터, 맵, 집합 모두 각각의 요소들이 다른 타입으로 들어가도 상관없습니다. 첫 번째 요소는 정수이고, 두 번째 요소는 문자열이라든가 하는 식으로 마구 섞여있어도 무관합니다. 그리고, 모든 자료구조가 그 안에 다른 자료 구조를 중첩해 포함하고 있어도 됩니다. 해쉬(오브젝트)와 어레이가 있는 JSON과 매우 비슷합니다. 다만 해쉬의 키값에 어떤 값이 와도 괜찮다는 점이 조금 더 확장된 거지요.

다시 동적인 개발 환경 설명으로 돌아오겠습니다. 이 그림은, 자바 같은 보통 컴파일 방식의 언어가 동작하는 흐름을 그린 모습입니다. 보통은 개발을 하는 프로세스와 컴파일 프로세스와 실행 프로세스가 각각 따로 떠서 주기를 반복합니다. 분홍색으로 표현한 부분이 실제 운영 중에 활용되는 별도의 JVM 프로세스일 테고요.

그러나, 클로저는 그 흐름이 일반적인 컴파일러 방식과 좀 다릅니다. 먼저 리더(Reader)가 있어서, 소스파일에서 읽어 들인 문자들을 클로저 자체의 자료구조 (리스트, 벡터, 맵 등)으로 변환합니다. 그리고, 그 변환한 클로저 자료 구조를 평가기(컴파일러)가 받아서 자바 바이트코드로 컴파일해냅니다. 런타임에 생성한 바이트코드를 그때그때 JVM이 받아서 실제 효과로 이어지지요. (실제 운영을 위해서는 AOT 컴파일링으로 미리 컴파일해둘 수 있습니다만) 개발 중에는 소스를 읽고, 평가하고 컴파일하고, 실행하는 과정이 한 프로세스에서 유기적으로 반복됩니다. 그 개발 흐름의 주기가 인터프리터처럼 동적이고 몰입하기 쉬운 컴파일러 방식인 거죠. 인터프리터 언어의 즉각적 반응과 컴파일러 언어의 빼어난 성능을 모두 취했습니다.

클로저 평가기(컴파일러) 입장에서는 컴파일하기 위해서 읽어 들이는 게 소스코드의 문자들이 아니라, 자료 구조입니다. 여타 언어의 AST를 받는 형태가 조금 바깥에 노출돼 있는 건데, 그 자료 구조가 클로저 자체의 기본 자료 구조라서 다루기 쉽습니다.

리더가 문자를 받아서 자료 구조를 만들어 내는데, 가만 보면, 이 문자들을 꼭 소스파일에서만 와야 할 이유는 없습니다. 그래서 그 클로저 코드를 개발자가 그 자리에서 즉시즉시 입력하는 걸 레플에서 read가 받는 거지요. 개발 과정에서 코드를 만들어 나가는 과정에서 실험해보고 확인해보며 잘 동작하는 함수를 만들어 내는 게 쉬워집니다.

이런 형태가 개발 흐름에 큰 도움이 된다라는 주장에 동의한다고 가정할 때, 같은 방식을 다른 언어 환경에서도 흉내 낼 수 있습니다. 그러나 차이점은, 클로저에서는 이게 기본인 거고, 내가 별도로 신경 써 설정할 필요 없이 기본이라는 점이 인상적입니다. 게다가 가장 독특한 것은, 언어 코드가 스스로의 자료 구조로 되어있다는 점입니다. 어떤 다른 언어도 이 점을 흉내 낼 수 없습니다. 흉내 내는 순간, 그 언어도 리스프가 되어버리니까요.

따라 하면 아류가 된다. 너만의 길을 가렴.

리더가 별도로 명확하게 분리돼 있어서 좋은 점이 있습니다. 코드나 사람에서 읽어 들이는 문자 수준의 코드가 아니라, 쉽게 구성해 놓은 자료구조를 평가기에 던지면 클로저 코드가 평가되고 컴파일되므로, 프로그램을 만드는 프로그램, 이른바 메타프로그래밍이 쉽습니다.

내가 원하는 문법을 별도의 AST로 구성하고, 그걸 다시 캐릭터로 애써 뱉어내고, 그걸 다시 컴파일러 시스템이 텍스트를 읽어 파서를 돌리는 게 아니라, 그냥 자료 구조로 구성하고 변환하며 던지면 됩니다.

단방향으로 자료구조를 내보내는 메타 프로그래밍에서 한 단계 더 나아가 매크로가 있습니다. 매크로는 평가기가 중간중간 매크로 입력을 받으면, 매크로에게 변환을 요청하고, 매크로가 반환한 자료구조를 평가기가 되받아 평가합니다. 매크로가 변환한 결과가 다시 매크로일 수도 있으니, 여러 번 반복해 최종적으로 다른 함수나 특수 폼으로 귀결합니다.

Recursion, Recursion!

게다가 이 문법 자료 구조라는 것이 특출 날 것 없는 평범한 클로저 코드에서 활용하는 기본 자료 구조이기에, 이미 클로저에 있는 함수처럼 매크로를 작성하고, 매크로에서 자료구조를 변환할 때에도, 이미 있는 map, filter, conj, concat 등 다수 기본 함수를 편리하게 활용합니다. 매크로는 단순히 보면, 클로저 문법 자료 구조를 받아서, 다시 조금 다른 형태의 문법 자료구조를 돌려주는 함수에 불과합니다.

이걸 언제 해? 컴파일 타임에.
컴파일은 언제 해? 런타임에.
OMG.

이런 매크로를 이용자가 아주 함수처럼 편리하게 만들 수 있기에, 새로운 문법을 추가하는 것도 편리하게 할 수 있어요. 여타 언어에서, 어떤 추가적 문법 기능이 필요하다고 할 때, 언어 제작자나 커뮤니티에 부탁하고 설득하고 반영되기를 기다리는 것이 아니라, 그냥 누군가 만든 라이브러리를 가져다 쓰면 됩니다. 없으면 만들어도 되고요.

모든 권한을 주마. 사실 원래 네 것이었지만.

이 문법이 물론 거창한 새 문법을 말하는 것일 수도 있지만 아주 단순한 기능으로 코드 곳곳에 중복되는 내용들을 간단히 줄여주는 추상화도 도와줍니다. 고차 함수 (Higher Order Functions)수준으로도 줄일 수 없는 중복도 매크로로는 간단히 없앨 수도 있어서. 우리 개발자가 좋아하는 DRY 원칙을 따르기 쉽습니다.

Don’t Repeat Yourself.

문법 구조는 매우 간단합니다. 오로지 괄호로 감싼 리스트가 전부라고 해도 과언이 아닙니다. 이 점을 얘기할 때, 리스프는 문법이 없다라고도 하는데, 그건 좀 과장인 게, 사실 문법이 없는 대신 알아야 할 함수나 매크로가 많으니까요. 문법이나 연산자로 하는 일들을 함수나 매크로로 일관되고 단순하게 처리하는 거예요.

암튼, 문법을 해석하는 측면에서는 리스트가 있고, 리스트의 첫번 째 요소로 심볼이 나오고 그 이하 여러(0개 이상) 값이 따라옵니다. 그 해석한 문법을 실행하는 입장에서 볼 때는, 괄호로 감싼 것은 호출을 의미합니다. 리스트 첫째 요소의 심볼이 지칭하는 함수/특수 폼/매크로를 실행하며, 실행을 요청할 때 인자로 나머지 값들을 전달합니다.

함수 호출, 그게 전부임.

일반적 언어에서, 괄호가 함수 이름 다음에 나오는 것과 좀 차이가 있어 이질적입니다만, 사실 괄호의 위치가 한 단계 앞으로 나왔을 뿐입니다. +기호도 연산자로 보자면, 평소 쓰는 중위식(infix)이 아니라서 어색하지만, 사실 +가 addition을 의미하는 함수이므로, addmul 같은 지시자로 풀어쓰면 어렵지 않게 이해됩니다.

하지만, 분명, 이미 다른 언어로 개발하던 입장에서는 이질적으로 느껴지는 것은 어쩔 수 없지요.

그런데, 곧 괄호가 좋아지는 마법.

클로저 같은 함수형 프로그래밍에 대한 관심이 계속 늘어가는 것 같은데요, 굳이 기존 절차형 프로그래밍 스타일과 많이 달라서, 어렵게 느껴지는 함수형 프로그래밍을 강조하는 이유가 뭘까요? 아마도 겉보기에 어렵다는 점과 달리, 실제 해보면 프로그래밍 로직을 이해하고 생각하기 쉽고, 함수 단위로 입출력을 상태와 별도로 단순한 값들로 다루기에 테스트하기가 쉽습니다. 어떤 특정 상황을 test fixture로 만들거나 가짜 mock 오브젝트를 만드느라 수고할 필요가 없습니다.

게다가 단순한 값들을 불변으로 다루기에 동시성 처리에 큰 도움이 됩니다.

불변 자료는 한번 만들면 바꾸지 않는 데이터를 말합니다. 상수처럼 바뀌지 않는 값이지만, 미리 정적으로 정해놓아야 하는 것은 아니고, 실행 중에 동적으로 만듭니다. 언제든 최초 한번 생성하고 나면 더 이상 바꾸지 않는 값입니다. 상수와 마찬가지로 바뀌지 않는 값이기에 어느 스레드에서 동기화 없이 접근해도 괜찮습니다. 지금 내 스레드는 물론 다른 스레드에서도 값을 바꾸지 못하기 때문에 본질적으로 스레드에 안전한 거죠.

Thread-safe!

불변 자료는 원래 값에서 조금 바꾼 값이 필요할 때, 원래 자료는 그대로 두고, 새 버전을 만들면서 바꿀 값을 반영하는 데요, 예를 들어 불변 리스트를 다룰 때 새 요소를 덧붙이려 한다면, 가장 간단한 방법은 원래 리스트의 전체를 복사하면서 맨 앞에 요소를 추가하는 새 리스트를 만들어 내는 방법입니다만, 그러면, 메모리와 속도 측면 모두에서 비효율적이라는 문제가 있습니다.

그 문제를 해결하기 위해, 불변 자료의 장점을 취하면서도 성능이나 메모리 측면에서 효율을 꾀하려, 불변 자료 간 구조를 공유하는 영속 자료구조라는 것을 씁니다. 각각의 불변 자료가 공유할 수 있는 부분들을 공유해서 메모리 낭비를 줄이고, 시간 복잡도 측면에서도 변이 자료 구조에서의 알고리즘 성능에 뒤처지지 않는 알고리즘을 씁니다.

그래서 효율적으로 스레드에 안전하고, 자료구조의 전체를 순회하는 처리를 할 때도 별도의 동기화나 걱정이 없이 처리하게 되어 매우 편리합니다.

예를 들어, 영속 퍼시스턴스 리스트를 살펴보겠습니다. 고려말 조선초 왕위를 간단하게 리스트로 표현해서, 공양왕 왕요에 이어, 이성계가 왕이 된 상황을 리스트 A로 가리키고 있는 상황인데요.

여기에 이방석이 세자로 책봉되는 상황을 리스트 B로 만들면, 리스트 B는 리스트 A에 있는 두 개 요소를 공유하고, 만 앞에 이방석을 추가할 수 있습니다. 그러면서도 리스트 A는 원래대로 접근할 수 있고, 값도 바뀌지 않습니다. B의 입장에서도 A가 가르키던 내용들이 불변이기 때문에 안심하고 쓸 수 있습니다.

이 상황에 이방원이 왕자의 난을 일으켜, 형님 이방과를 왕위에 앉게 하는데요, 그리고 곧 본인이 3대 태종으로 즉위하는데, 그렇게 되면 리스트 C가 실제 왕위를 나타내게 됩니다. 리스트 B가 잠시 왕위 흐름도가 될 뻔하다가, 역사는 리스트 C가 된 거지요.

불변 영속 자료구조는 이런 식으로 원래 값들에 계속 문제없이 안전하게 접근할 수 있으면서도 메모리와 성능 측면에서도 나쁘지 않게 활용합니다. 여타 프로그래밍 언어에서도, 불변 영속 자료구조를 별도 라이브러리로 가져다 쓰는 경우가 많습니다만, 클로저는, 언어 기본 자료구조가 불변 영속이라는 점이 특징입니다. 옵션이 아니라 기본이고 필수인 거지요.

동시성(concurrency)과 병렬 처리(parallelism)을 구분하면 이해하기 좋은데요, 병렬처리는 그저 서로 상관없는 일들을 동시에 처리하면 병렬 처리인 거고, 동시성은 동시에 처리하면서 서로 데이터를 주고받거나 공유해서 조화롭게 처리해야 하는 겁니다. 한 머신, 특히 한 프로세스 내에서 멀티스레드로 동시에 작업을 할 때에는 여러 스레드가 같은 메모리 공간을 공유하기에, 한 스레드가 처리하고 있는 데이터를 다른 스레드가 중간에 바꿔버리는 문제가 생길 수 있습니다.

사실 메모리 공간을 공유하는 것 자체는 문제가 아닙니다만, 함께 쓰는 걸 누군가 막 바꾸는 것이 문제입니다. 그래서 멀티스레드 환경에서 공유하는 데이터에 접근할 때에는 락을 잡고 접근하고 락을 푸는 방법을 흔히 씁니다. 하지만, 이게 잘 처리하기 매우 어려운 일이죠.

정리하자면, 여타 프로그래밍 환경에서는 보통, 변이 대상에 멀티 스레드가 직접 접근하면서 동기화 처리를 하는데, 이른바 락을 잠그고 잘 되길 바라는 전략을 씁니다. 직업적으로 해보신 분들은 아시겠지만, 이게 절대 쉬운 일이 아닙니다. 잠그고 잘 되길 바라는 정도이지, 정말 문제없이 잘 될지 확신이 들지 않아 불안합니다. 내가 아무리 잘해도 옆 신입이 실수하면 전체가 망가지는 거죠. 반대로 옆 자리 코딩의 신이 암만 잘 해 놔도, 내가 자칫 실수하면 다 같이 망가지고요.

반면 클로저에서는 불변 자료 구조를 참조하는 간접적인 방법을 쓰고, 그 참조 과정에 동시성 처리를 자동으로, 그리고 강제적으로 합니다. 일일이 수동으로 하는 잠금 처리가 필요없기 때문에, 훨씬 편하고 불안 없이 처리하면서도 동시성 처리를 다룰 수 있습니다. 아무 생각 없이 멀티 스레디드 애플리케이션을 짤 수 있다는 뜻은 아닙니다만, 분명 보통의 방법보다는 훨씬 우아하고 탄탄하게 작성할 수 있습니다.

클로저에서 언어 기본적으로 지원하는 동시성 처리를 위한 참조형들입니다. 동기/비동기에 따라 단독으로 처리할 때 쓰는 atom과 agent가 있고, 메모리에서 여러 레퍼런스 간 트랜잭션 처리를 다루는 ref도 있습니다. STM이라고 말하는 Ref는 데이터베이스 트랜잭션 처리, ACID와 비슷한데, 디스크에 저장하지 않고 메모리에서의 트랜잭션 처리를 한다고 생각하시면 될 것 같습니다.

그 밖에도, 여러 매력적인 특징들이 있습니다만, 소개는 여기까지만 하겠습니다.

그래서 클로저 소개를 요약하자면, JVM 환경에서 실행되므로, 이미 자바 환경이 쓰이고 있는 현업에서 활용하기 좋은 실용적 언어이고, 리스프의 이상적인 매력도 공유하고 있으며, 함수형 프로그래밍을 추구하면서 기본 동시성 지원 기능이 있어서, 현대의 고성능 프로그램을 적확하게 개발하기 좋습니다. 그리고 대화식 개발 환경을 바탕으로 부드럽게 몰입 상태에 빠져들며 즐겁게 개발하기 좋은 언어라고 말씀드리고 싶습니다.

Part 2. 클로저 개발 환경.

다음으로, 언어의 기본을 익히고 나면, 이어서 그 언어 생태계에서 쓰는 개발 도구나 준표준 라이브러리를 알아야 실용적으로 활용할 수 있을 텐데요, 몇 가지 기본적인 툴을 소개하겠습니다.

먼저 가장 중요한 빌드 툴인데요, 자바의 메이븐, 노드의 npm처럼, 라이브러리 디펜던시 관리와 프로젝트 빌드를 자동화하는 라이닝은('라인'이라고 줄여 부릅니다)과 부트가 있습니다. 라인은 클로저 edn 표현으로 미리 정해진 선언적 값을 바탕으로 빌드 프로세스를 관리합니다. 한편, 부트는 빌드 프로세스도 프로그램이라고 여겨서 클로저 프로그래밍 코드로 기술합니다.

클로저 커뮤니티 전반적으로 둘 다 널리 쓰여서 뭘 쓰든 크게 문제없으니, 본인 스타일에 맞게 골라 쓰시면 되고, 고르기도 번거롭다면 그냥 라이닝은을 선택하시면 되겠습니다.

라인과 부트 둘 다 자바의 메이븐 리포지토리를 쓰기 때문에, 각종 자바 라이브러리 디펜던시를 아주 간단하게 충족할 수 있습니다. 다른 자바 환경과는 무관하게 순수 클로저에만 한정된 라이브러리의 경우 클로자스(Clojars)에 공개되는데, 크게 신경 쓰지 않아도 둘 중 어디서든 알아서 찾아서 내려받아 줍니다. 메이븐 리포지토리 시스템을 그대로 쓰기에, 만약 사내 인프라에만 공유되는 비공개 리포지토리가 있더라도 문제없이 연결해서 쓸 수 있습니다.

다음으로 IDE, 통합개발환경이나 에디터 플러그인을 소개해드리겠습니다. 사실 클로저를 주변 분들에게 소개할 때, 가장 자신 없는 부분이 이 부분인 것 같습니다. 인텔리J기반의 Cursive가 꽤 강력하다는데, 유료라서 처음 시작할 때는 약간의 부담이 있고요, 무료 오픈소스이면서 가장 강력한 사이더는, 이맥스를 써야 한다는 큰 벽이 있습니다. 평소 이맥스를 쓰시는 분들이야 문제없지만, 그렇지 않은 분들께, 클로저를 쓰기 위해 이맥스를 익히라고 말하기엔 스스로도 납득하기 어려운 거지요.

클로저를 쓰려면 이맥스부터 익히고 오라고?! 읭?

그다음으로는 아마도 Atom 에디터 (클로저 atom과 무관하고, 깃헙에서 공개한 텍스트 에디터)에 클로저용 플러그인을 깔아서 쓰는 게 지금으로선 꽤 괜찮은 방법이 아닌가 합니다. 다른 분들은 뭘 추천하실는지 저도 궁금합니다.

https://gist.github.com/jasongilman/d1f70507bed021b48625

이번 발표를 준비하면서, 그나마 좀 친숙할 것 같은 아톰으로 설정해봤는데, protorepl이라는 플러그인이 꽤 괜찮아서 처음 클로저로 개발하시기에는 괜찮을 것 같습니다. 깃헙 기스트에서 Atom Clojure로 검색해 보시면, 프로토레플 제작자가 잘 정리해둔 아톰에서의 클로저 개발환경 설정법이 있으니, 따라서 해보시면 쉽게 쓰실 수 있지 않을까 합니다.

다음으로, 클로저 개발하면서 살펴볼 웹사이트 몇 군데 소개해드릴게요. 저는 가장 많이 참고하는 페이지가 이 치트시트 페이지인데, 클로저에서 쓰는 각종 코어 함수들이 여기에 정리돼 있어서, 틈틈이 보면서 개발합니다.

클로저 닥스도 아주 잘 정리돼 있고, 여기는 커뮤니티 사람들이 예제를 달아둬서 용례를 익히기 좋은 것 같습니다. 검색해서 관련 함수를 찾기도 좋고요.

클로저 기본 문법을 익히고 난 다음에 참고해볼 만한 사이트는, 4클로저라고, 여기에 각종 문제집이 있고, 내가 온라인에서 클로저로 해당 문제를 풀어보기도 하고, 다른 사람들은 어떻게 풀었나 참고하면서 클로저의 코딩 스타일을 배우기 좋은 것 같습니다. 난이도별로 문제를 골라서 풀어 볼 수 있습니다.

Part 3. 클로저 문법 기초 코딩 데모.

이렇게 클로저 특징 소개와, 관련 생태계를 아주 간단히 살펴봤고, 이제부터 실제 코드를 보면서 설명드릴 건데요, 라이브 코딩이 매끄럽게 진행되는 경우는 드물죠? 그리고 시간이 많지 않기 때문에, 준비한 코드를 시간이 되는 데까지만 쭈욱 살펴보겠습니다.

여기 깃헙 저장소에 올려놓은 코드이므로, 소스를 직접 보실 수 있으니 참고하시고요,

https://github.com/hatemogi/clojure-quick-intro

코딩에 앞서 레플에서의 개발환경이 좀 독특하기 때문에, 간략히 상황 설명 먼저 드리겠습니다. 터미널에서 lein repl이라고 실행해서, 현재 예제 프로젝트 환경의 레플 프로세스를 띄울 거고요, 이 레플 프로세스는 JVM으로 기동 되며, 클로저 리더와 평가&컴파일러가 준비된 상황입니다. 우리가 개발하는 코드도 필요한 부분이 미리 로드된 상황입니다.

여기에 TCP 소켓으로 별도의 아톰 프로세스가 REPL 커넥션을 연결합니다. 그러면, 나름의 레플 컨텍스트 (현재 작업 중인 기본 이름 공간을 비롯한 문맥)가 할당되고, 내가 레플로 전달하는 문자들이 클로저 리더에 의해 자료구조로 바뀌고, 그 자료구조가 평가기를 거쳐 바이트코드로 떨어집니다. 그 바이트 코트를 이미 기동 중인 JVM이 실행해서 효과로 드러나는 것입니다.

코딩 내용은 라이브로 진행했습니다. 프로젝트 소스 core.clj를 열어 한 줄씩(정확히는 한 괄호쌍마다) 실행해보며 따라 하면 클로저 기본 문법을 이해하기에 좋고. RDB를 다루는 예제는 db.clj에, 웹서비스를 만드는 예제는 web.clj에 준비해 두었습니다. 발표시간 조절을 잘 못해서, 소스코드는 아주 일부만 빠르게 훑고 넘어가서 아쉽네요.

이건 조만간 스크린캐스트를 찍어 유튜브에 공유하고 링크 걸게요. 사실 이게 젤 재밌는 부분이니까요.


이상 제6회 리스프 세미나에서 발표했던 내용을 공유합니다. 사실 여느 발표와 달리 잘하고 싶다는 욕심이 컸는데, 그만큼 클로저 언어나 애정이 컸나 봅니다. 여느 언어나 커뮤니티와 애증의 연애를 몇 번 거치고 나면, 사실 언어가 그렇게 중요한 것은 아니라고 느끼곤 하는데, 클로저는 워낙 매력적인 언어이다 보니 다시 또 홀라당 빠져버렸나 봅니다.

언젠가 기회가 되면, 또 클로저 소개나, 아니면 자바 같은 언어에서 클로저 스타일로 코딩하는 법을 소개해드리고 싶습니다.

끝으로, 여러모로 힘든 일이 많았을 텐데, 세미나를 개최해주고 운영해주신 관련자 분들과, D2 스타트업 지원 부서, 그리고 무엇보다, 황금 주말 시간에 개인 시간 할애해 참석해 경청해주신 참가자 분들께 감사드립니다. 개인적으로는 오랜만에 뵙는 반가운 얼굴들과, 새로 인사해주신 미디엄 구독자 분들께도 고마운 마음 전합니다.

고맙수당~ 즐거웠어요.

이상, 아주 긴 글 읽어주셔서 감사합니다. 마음에 든 부분이 있었다면 아래 박수 버튼 세 번 누르시고, 페북이나 트위터에 공유해주시고, 클로저 책 한 권 주문하러 가십시다. 뿅~!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.