
Clojure의 우아함과 C++의 야성미를 동시에? Jank 언어 알파 출시를 보며
Clojure의 생산성과 C++의 성능을 결합한 LLVM 기반의 네이티브 Clojure 방언, Jank 언어의 알파 출시 소식과 주요 특징을 소개합니다.
김영태
테크리드

안녕하세요. 풀링포레스트 테크리드 김영태입니다.
개발자라면 누구나 한 번쯤 "이 두 마리 토끼를 다 잡을 순 없을까?"라는 고민에 빠집니다. 저에게는 그게 바로 '생산성(추상화)'과 '성능(제어권)' 사이의 줄다리기였습니다. 풀링포레스트에서 백엔드 시스템을 설계하다 보면, 비즈니스 로직은 유연한 고수준 언어로 빠르게 짜고 싶으면서도, 동시에 트래픽이 몰리는 병목 구간에서는 C++ 같은 저수준 언어의 날카로운 성능이 절실해질 때가 있거든요.
솔직히 고백하자면, 예전에 사내 이미지 처리 모듈을 최적화하겠답시고 JNI(Java Native Interface)를 건드렸다가 디버깅 지옥에 빠져 며칠 밤을 새운 적이 있습니다. 그때 뼈저리게 느꼈죠. "서로 다른 런타임의 언어를 붙이는 건, 정말 신중해야 하는구나."
그런데 최근 제 눈을 의심하게 만드는 흥미로운 프로젝트 하나가 알파(Alpha) 버전을 출시했습니다. 바로 Jank(장크)라는 언어입니다.
Clojure 문법에 C++ 심장을 달다
Jank를 한 문장으로 정의하면 이렇습니다.
"LLVM 위에 호스팅되고, C++과 매끄럽게(Seamless) 상호운용이 가능한 네이티브 Clojure 방언."
이게 무슨 뜻일까요? 기존에 우리가 알던 Clojure는 JVM(Java Virtual Machine) 위에서 돌아갑니다. 덕분에 Java 라이브러리를 마음껏 가져다 쓸 수 있었죠. 하지만 JVM의 무거운 초기 구동 속도와 메모리 사용량, 그리고 네이티브 레벨의 제어가 어렵다는 단점이 늘 꼬리표처럼 따라다녔습니다.
Jank는 이 판을 바꿉니다. JVM 대신 LLVM을 선택했습니다. 즉, Java 바이트코드가 아니라 네이티브 기계어로 컴파일된다는 뜻입니다.

개발팀이 내건 슬로건이 아주 직관적입니다.
"Clojure의 호스트가 JVM이고 상호운용 대상이 Java라면, Jank의 호스트는 LLVM이고 상호운용 대상은 C++이다."
왜 주목해야 할까요?
제가 이 언어를 보고 소름이 돋았던 이유는 단 하나, 'C++ 라이브러리를 Lisp의 REPL(Read-Eval-Print Loop) 환경에서 가지고 놀 수 있다'는 점 때문입니다.
C++은 강력하지만 까다롭습니다. 컴파일 시간도 길고, 코드를 작성하고 결과를 확인하는 피드백 루프가 깁니다. 반면 Clojure 같은 Lisp 계열 언어는 코드를 한 줄 실행하면 바로 결과가 나오는 인터랙티브한 개발이 강점이죠. Jank는 C++의 라이브러리나 무거운 그래픽/연산 라이브러리를 마치 스크립트 언어 다루듯 즉석에서 실행하고 테스트해볼 수 있게 해줍니다.
백문이 불여일견, Jank의 README에 올라온 예제 코드를 한번 보시죠.
; 기본적인 Clojure 문법은 그대로입니다. (불변 데이터 구조)
(def george {:name "George Clooney"})
(defn say-hi [who]
(println (str "Hi " (:name who) "!")))
; 여기서부터가 진짜입니다. C++ 네이티브 상호운용!
(defn sleep [ms]
(let [duration (cpp/std.chrono.milliseconds ms)]
(cpp/std.this_thread.sleep_for duration)))보이시나요? 나 같은 네이티브 C++ 네임스페이스를 별도의 래퍼(Wrapper) 코드나 복잡한 설정 없이 바로 호출하고 있습니다. 예전 같으면 헤더 파일 링킹하고, 바인딩 코드 짜느라 반나절은 보냈을 작업을 단 몇 줄로 끝내는 겁니다.
아직은 '알파' 단계, 하지만...
물론 지금 당장 우리 팀의 프로덕션 코드에 Jank를 도입하자는 건 아닙니다. 이제 막 알파 딱지를 붙인 단계고, 생태계도 초기 상태니까요. 문서도 아직 부족하고, 예상치 못한 버그(말 그대로 janky한 상황)를 마주할 수도 있습니다.
하지만 인프라와 백엔드를 다루는 입장에서 이 시도는 시사하는 바가 큽니다.
Serverless/FaaS 환경: JVM의 콜드 스타트(Cold Start) 문제 때문에 Clojure 사용을 꺼렸던 곳에, 네이티브로 컴파일되는 Jank가 대안이 될 수 있습니다.
시스템 프로그래밍의 진입 장벽 완화: C++의 성능이 필요하지만 C++의 문법적 복잡함이 싫었던 개발자들에게, Lisp의 강력한 매크로와 함수형 패러다임으로 시스템을 제어할 수 있는 길을 열어줍니다.
마치며
풀링포레스트에서도 레거시 시스템을 모던하게 개편하는 과정에서 늘 '언어의 선택'에 대해 치열하게 고민합니다. 무조건 메이저 언어(Java, Python)만 고집할 것이 아니라, 이렇게 '생산성'과 '성능'의 경계를 허무는 새로운 도구들에 관심을 가지는 자세가 필요합니다. 그래야 남들이 "안 된다"고 할 때 "이런 방법이 있습니다"라고 제안할 수 있는 엔지니어가 될 수 있으니까요.
Clojure나 Lisp에 관심이 없으셨던 분이라도, C++을 REPL에서 가지고 노는 이 기묘한 경험은 꼭 한번 눈여겨보시길 바랍니다. 기술의 발전은 언제나 "불편함을 참지 못하는" 지점에서 시작되니까요.
저도 이번 주말에는 로컬에 Jank를 설치해서, 평소 다루기 힘들었던 C++ 라이브러리를 Lisp 문법으로 쪼물딱거려볼 생각입니다. 혹시 재미있는 결과물이 나오면 다시 공유해 드리겠습니다.
감사합니다.


