Skip to content
Published on

모던 Clojure 2026 완벽 가이드 — Clojure 1.12 · Babashka · ClojureScript · shadow-cljs · Datomic · XTDB · re-frame 심층 분석

Authors

프롤로그 — 왜 2026년에 Clojure인가

2026년 5월, 누군가 "요즘 Lisp을 쓰는 사람이 있나?"라고 묻는다면, 답은 명확하다. 있다, 그것도 아주 많다. 브라질의 Nubank는 1억 1,000만 명의 고객을 보유한 세계 최대 디지털 은행이며, 그들의 백엔드는 거의 전체가 Clojure로 작성되어 있다. 마이크로서비스가 5,000개를 넘고, 매일 수십억 건의 트랜잭션을 처리한다. CircleCI는 CI/CD 파이프라인 코어를, Apple은 일부 내부 도구를, Cisco는 네트워크 분석 플랫폼을, Walmart Labs는 가격 엔진을 Clojure로 돌린다.

Clojure는 2007년 Rich Hickey가 발표한 후 20년 가까이 같은 철학을 유지해 왔다. 불변(immutable) 우선, 함수형, 동적 타입, JVM 호스트, 동시성을 일급 시민으로. 그러나 2020년대 들어 Clojure 생태계는 조용히 진화했다. Leiningen 단일 빌드 시대를 지나 deps.edntools.deps가 표준이 됐고, ClojureScript는 shadow-cljs를 통해 npm 생태계를 통째로 흡수했다. Babashka는 GraalVM 네이티브 이미지로 컴파일되어 시작 속도가 ~20ms — Python보다 빠르다. 셸 스크립트 시장에서 Bash와 Python을 동시에 위협한다.

2026년 5월, Clojure 1.12가 안정화되면서 qualified method invocation 같은 자바 상호운용성 개선이 들어왔고, partialloop가 더 똑똑해졌다. ClojureScript 측에서는 shadow-cljs 2.x가 React 18·Vite 6·esbuild 통합을 다듬었고, re-frame 1.4는 이펙트·이벤트 모델을 더 매끈하게 만들었다. Datomic은 Pro 라이선스가 사실상 무료가 되었고(Cloud는 유료 유지), XTDB 2.0은 bitemporal에 SQL-first를 더해 PostgreSQL 사용자에게도 접근 가능해졌다.

그리고 결정적으로, LLM 시대가 Clojure에 의외의 순풍을 불어넣었다. REPL 주도 개발은 본질적으로 "한 표현식씩 평가하고 결과를 본다"의 반복이다. LLM이 코드를 생성하고 사람이 한 단계씩 검증하는 워크플로와 완벽히 맞는다. Cursive·Calva·CIDER 같은 에디터들은 LLM 통합을 강화했고, REPL에서 LLM 응답을 직접 평가하는 패턴이 자리 잡았다.

이 글은 Clojure 2026의 전체 그림을 한 글로 정리한다. 언어 자체 → 빌드/배포 → 백엔드 스택 → 프런트엔드 → 데이터베이스 → 테스팅 → 에디터/REPL → 실전 운영. Nubank가 어떻게 5,000개 마이크로서비스를 굴리는지, 한국·일본 커뮤니티가 어디까지 왔는지, 그리고 2026년에 새로 시작하는 사람이 어떤 스택부터 잡아야 하는지까지 짚는다.

Clojure는 "쓰는 사람이 적은 언어"가 아니다. **"안 보이는 곳에서 무거운 트래픽을 받는 언어"**다. 보여지는 라우저들의 자바스크립트 백엔드가 1% 시장이라면, 보이지 않는 1%의 백엔드가 Clojure다.

가격·버전 숫자는 빠르게 바뀐다. 이 글의 모든 수치는 2026년 5월 기준이며, 구조적 차이에 집중한다. 6개월 뒤 마이너 버전이 바뀌어도 의사결정 프레임은 유효해야 한다.


1장 · Clojure 1.12 — 무엇이 바뀌었고 왜 중요한가

Clojure 1.12는 2024년 9월에 처음 릴리즈됐고, 2026년 5월 시점에는 1.12.x 패치가 안정화되어 사실상 표준이다. 핵심 변화 세 가지를 본다.

Qualified method invocation 자바 상호운용성에서 가장 큰 변화다. 기존에는 (.method obj arg) 형태로만 호출 가능했고, 메서드를 함수처럼 다루려면 #(.method % arg) 같은 람다 래퍼가 필요했다. 1.12부터는 메서드를 값으로 취급할 수 있다.

;; 이전 (1.11 이하)
(map #(.toUpperCase %) ["foo" "bar" "baz"])
;; => ("FOO" "BAR" "BAZ")

;; 1.12 — qualified method invocation
(map String/.toUpperCase ["foo" "bar" "baz"])
;; => ("FOO" "BAR" "BAZ")

;; 정적 메서드
(map Math/abs [-1 -2 3])
;; => (1 2 3)

;; 생성자도 마찬가지
(map StringBuilder/new ["hello" "world"])

String/.toUpperCase처럼 Class/.method 형태가 인스턴스 메서드, Class/method가 정적 메서드 또는 생성자다. 자바 람다와 비슷한 느낌이지만, Clojure 의미론을 지킨다.

partial의 인라인 최적화 (partial f x)는 새 함수를 만들어 반환한다. 1.12부터는 컴파일러가 인라인할 수 있는 경우 람다와 동등한 성능을 낸다. 핫 패스에서 partial을 자유롭게 쓸 수 있게 됐다.

loop의 타입 힌트 보존 loop/recur 사이클에서 타입 힌트가 사라지던 문제가 수정됐다. 수치 계산 코드에서 박싱이 줄어 5~15% 성능 개선이 보고된다.

기타: clojure.core/iteration — lazy seq의 일반화. update-vals, update-keys — 맵 변환 헬퍼. add-tap — 디버깅 훅 표준화. random-uuid — 깔끔한 UUID 생성기.

Clojure 1.12는 "혁명"이 아니라 "수공구가 더 잘 갈렸다"는 느낌의 릴리즈다. 그러나 자바 상호운용성이 매끈해진 건 큰 일이다. 자바 라이브러리를 부담 없이 호출할 수 있게 됐다.


2장 · tools.deps와 deps.edn — Leiningen 이후의 빌드

오랜 Clojure 사용자들에게 project.clj(Leiningen)는 익숙하다. 그러나 2026년 신규 프로젝트의 ~70%는 deps.edntools.deps를 쓴다. 차이를 본다.

deps.edn 기본 구조

;; deps.edn
{:paths ["src" "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.12.0"}
        ring/ring-core      {:mvn/version "1.11.0"}
        metosin/reitit      {:mvn/version "0.7.0"}}
 :aliases
 {:dev {:extra-paths ["dev" "test"]
        :extra-deps {nrepl/nrepl {:mvn/version "1.3.0"}
                     cider/cider-nrepl {:mvn/version "0.47.0"}}}
  :test {:extra-paths ["test"]
         :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.0"}}
         :main-opts ["-m" "kaocha.runner"]}}}

clj -X:dev 같은 alias 호출로 다양한 실행 모드를 정의한다. Maven 좌표를 그대로 쓸 수 있고, Git 좌표도 1급 지원이다.

;; Git에서 직접 의존성
{:deps {io.github.somelibrary/lib
        {:git/url "https://github.com/somelibrary/lib.git"
         :git/sha "a1b2c3d4..."}}}

이게 왜 중요한가. Maven에 올라가지 않은 라이브러리, 포크한 라이브러리, 내부 라이브러리를 별도 인프라 없이 의존성으로 쓸 수 있다.

Leiningen은 죽었나 아니다. Leiningen은 여전히 큰 시장이 있다. lein 명령으로 repl, test, uberjar까지 한 줄로 끝난다. 학습 곡선이 더 부드럽고, project.clj는 데이터가 아닌 코드라 매크로로 더 유연하다. 단점: 시작 속도가 느리고(JVM + Lein 부팅 ~3초), Maven 중심이라 Git 좌표 같은 기능이 어색하다.

의사결정 가이드

  • 새 프로젝트 + 라이브러리 다양성 중요 → deps.edn
  • 기존 Leiningen 프로젝트 유지 → lein 그대로
  • 라이브러리 배포 → 둘 다 가능, 그러나 deps.edn + build.clj (tools.build) 조합이 점점 표준

tools.build build.clj라는 빌드 스크립트를 Clojure로 작성한다. Makepackage.json scripts와 비슷하지만 전부 Clojure다.

;; build.clj 일부
(ns build
  (:require [clojure.tools.build.api :as b]))

(def lib 'com.example/my-lib)
(def version "0.1.0")
(def class-dir "target/classes")

(defn clean [_]
  (b/delete {:path "target"}))

(defn jar [_]
  (b/write-pom {:class-dir class-dir
                :lib lib
                :version version})
  (b/jar {:class-dir class-dir
          :jar-file (format "target/%s-%s.jar" (name lib) version)}))

clj -T:build jar로 호출한다. 모든 빌드 단계가 Clojure 함수다.


3장 · Babashka 1.4 — Clojure가 들어간 셸

Babashka는 Michiel Borkent(borkdude)가 만든 GraalVM 네이티브 이미지로 컴파일된 Clojure 인터프리터다. 2026년 5월 기준 1.4.x가 안정 버전이며, 시작 속도가 20~30ms에 불과하다. Python(~50ms), Bash 스크립트(~10ms)와 경쟁할 만한 수준이다.

왜 셸 스크립트로 Clojure를? 세 가지 이유.

  1. 데이터 처리 — JSON, EDN, CSV, YAML이 모두 1급 시민. jq보다 표현력이 강하다.
  2. 에러 처리 — Bash의 set -e는 위험하다. Clojure의 예외와 try/catch로 견고한 스크립트.
  3. 이식성bb 바이너리 하나만 있으면 어디서나 같은 코드가 돈다.

실전 예시

#!/usr/bin/env bb

(require '[babashka.curl :as curl]
         '[cheshire.core :as json])

(defn fetch-github-stars [repo]
  (-> (curl/get (str "https://api.github.com/repos/" repo))
      :body
      (json/parse-string true)
      :stargazers_count))

(println "Stars:" (fetch-github-stars "clojure/clojure"))

bb script.clj 또는 chmod +x 후 직접 실행. JVM 없이 돈다.

bb tasks bb.edn 파일에 작업을 선언한다. npm run과 비슷한 느낌이지만 Clojure 전체를 쓸 수 있다.

;; bb.edn
{:tasks
 {test     (shell "clj -X:test")
  build    (shell "clj -T:build jar")
  deploy   {:depends [build]
            :task (shell "clj -T:build deploy")}
  clean    (shell "rm -rf target")}}

bb test, bb build, bb deploy처럼 호출. :depends로 작업 의존성을 선언할 수 있다.

nbb — Node Babashka Node.js 런타임 위에서 도는 Babashka. npm 패키지를 그대로 쓸 수 있다. Node 생태계를 Clojure로 짧은 스크립트 형태로 다루고 싶을 때.

;; nbb로 npm 패키지 호출
(require '["fs" :as fs])
(println (fs/readdirSync "."))

squint — CLJS to JS 컴파일 없이 Clojure식 문법을 JS로 직접 변환. JSX 안에서도 쓸 수 있다. 작은 도구에서 점점 인기를 끈다.

Babashka는 "Python을 대체하려는 게 아니라, Bash를 대체하고 싶다"고 borkdude가 말한 적 있다. 2026년에 그 야망은 충분히 현실적이다.


4장 · ClojureScript와 shadow-cljs 2.x — npm 생태계의 풀 액세스

ClojureScript는 Clojure 코드를 JavaScript로 컴파일하는 컴파일러다. 2026년 시점에 ClojureScript 개발의 ~80%는 shadow-cljs를 빌드 도구로 쓴다. Thomas Heller가 만든 이 도구의 핵심 가치는 npm 통합이다.

shadow-cljs 설정 예시

;; shadow-cljs.edn
{:source-paths ["src"]
 :dependencies [[reagent "1.2.0"]
                [re-frame "1.4.0"]
                [metosin/reitit-frontend "0.7.0"]]
 :builds
 {:app {:target :browser
        :modules {:main {:init-fn my-app.core/init}}
        :output-dir "public/js"
        :asset-path "/js"
        :devtools {:after-load my-app.core/reload!
                   :http-root "public"
                   :http-port 8080}}}}

npx shadow-cljs watch app로 시작하면 핫 리로드, REPL, 빌드가 동시에 도는 개발 서버가 뜬다. 빌드는 esbuild 기반이라 빠르다.

npm 패키지 직접 사용 shadow-cljs의 결정적 장점이다. package.json에 패키지를 추가하면 ClojureScript에서 즉시 import할 수 있다.

(ns my-app.charts
  (:require ["chart.js" :as Chart]
            ["d3" :as d3]))

(defn render-chart [el data]
  (Chart/new el (clj->js {:type "bar"
                          :data data})))

["chart.js" :as Chart] — 문자열 라이브러리 이름이 핵심. 일반 Clojure 의존성과 npm 패키지를 같은 require 안에서 섞을 수 있다.

Reagent — React 래퍼의 클래식 Reagent는 React 위의 가장 오래된 ClojureScript 래퍼다. Hiccup 문법으로 React 컴포넌트를 작성한다.

(ns my-app.ui
  (:require [reagent.core :as r]))

(defn counter []
  (let [n (r/atom 0)]
    (fn []
      [:div
       [:p "Count: " @n]
       [:button {:on-click #(swap! n inc)} "+1"]])))

[:div ...] 같은 벡터가 React element가 된다. r/atom은 mutable state를 표현하며 변경 시 자동 리렌더링. React 18의 동시성 기능까지 지원한다.

Helix — 새로운 React 래퍼 Helix는 Hook 우선 설계. defnc 매크로로 함수형 컴포넌트를 정의한다.

(ns my-app.helix-ui
  (:require [helix.core :refer [defnc $]]
            [helix.hooks :as hooks]
            [helix.dom :as d]))

(defnc Counter []
  (let [[n set-n] (hooks/use-state 0)]
    (d/div
      (d/p "Count: " n)
      (d/button {:on-click #(set-n inc)} "+1"))))

$ 매크로로 다른 컴포넌트를 렌더링. React Hooks와 1:1로 매핑된다. JSX보다 깔끔하다는 평이 많다.

UIx 2 — 가장 모던한 선택 UIx 2는 Helix와 비슷한 철학이지만 더 빠른 렌더링 최적화를 강조한다. SSR(server-side rendering) 지원, React Server Components 호환이 작업 중이다. 2026년 신규 ClojureScript 프로젝트의 ~30%가 UIx 2를 택한다.

(ns my-app.uix-ui
  (:require [uix.core :refer [defui $]]
            [uix.dom]))

(defui counter []
  (let [[n set-n] (uix.core/use-state 0)]
    ($ :div
      ($ :p "Count: " n)
      ($ :button {:on-click #(set-n inc)} "+1"))))

5장 · re-frame 1.4 — 큰 SPA의 상태 관리 답

Reagent로 카운터는 만들 수 있다. 그러나 100개 화면짜리 SPA에서 atom을 여러 컴포넌트에 흩뿌리면 디버깅이 지옥이 된다. re-frame은 그 답이다. Day8 팀이 만든 이 라이브러리는 ClojureScript의 사실상 표준 상태 관리다.

re-frame의 핵심 모델

  1. app-db — 모든 상태를 담은 단일 큰 맵
  2. events — 사용자 동작을 표현하는 키워드 (:user/login, :cart/add-item)
  3. handlers — event를 받아 app-db를 변환하는 순수 함수
  4. subscriptions — app-db에서 화면이 필요한 데이터를 뽑는 함수
  5. effects — 외부 세계와의 상호작용 (HTTP, localStorage, 타이머)
(ns my-app.events
  (:require [re-frame.core :as rf]))

;; 이벤트 핸들러
(rf/reg-event-db
 :user/login-success
 (fn [db [_ user]]
   (assoc db :current-user user)))

;; 서브스크립션
(rf/reg-sub
 :user/current
 (fn [db _]
   (:current-user db)))

;; 컴포넌트에서 사용
(defn user-panel []
  (let [user @(rf/subscribe [:user/current])]
    [:div "Hello, " (:name user)]))

;; 이벤트 디스패치
(rf/dispatch [:user/login-success {:name "Min-yong Kim"}])

왜 re-frame인가 세 가지.

  1. 시간 여행 디버깅 — re-frame-10x 라이브러리로 모든 event를 트레이스. 특정 시점의 상태로 되감을 수 있다.
  2. 순수 함수 우선 — handler가 순수 함수라 테스트하기 쉽다.
  3. 이펙트 격리 — HTTP 호출 같은 부수 효과가 명시적이라 테스트와 모킹이 깔끔하다.

re-frame 1.4의 변화

  • 인터셉터(interceptor) 체인 최적화 — 큰 앱에서 30% 빠른 디스패치
  • reg-fx에 비동기 이펙트 지원
  • Devtools 통합 강화 — Chrome Devtools 패널에서 event 트레이스

"Reagent + re-frame은 React + Redux의 Clojure 답이다. 그러나 Redux가 보일러플레이트 지옥인 데 반해, re-frame은 매크로로 같은 일을 더 짧게 한다." — Day8 팀의 공식 정리.


6장 · Pathom 3 — 그래프 쿼리의 새 표준

REST나 GraphQL을 쓰면 클라이언트가 필요한 데이터를 서버에 요청한다. 그러나 데이터가 여러 백엔드(DB, 외부 API, 캐시)에 흩어져 있을 때, "이 데이터를 어떻게 모을 것인가"는 항상 백엔드의 고민이다. Pathom 3은 그 문제를 그래프 리졸버 방식으로 풀어낸다.

Pathom 3의 모델 각 데이터를 어떻게 가져오는지를 resolver로 선언한다. 클라이언트는 EQL(EDN Query Language)로 필요한 데이터를 요청하고, Pathom이 리졸버 그래프를 탐색해 답을 모은다.

(require '[com.wsscode.pathom3.connect.indexes :as pci]
         '[com.wsscode.pathom3.connect.operation :as pco])

;; 리졸버 — user-id로 user 정보를 가져옴
(pco/defresolver user-by-id [{:keys [user-id]}]
  {::pco/output [:user/name :user/email]}
  (let [user (db/find-user user-id)]
    {:user/name (:name user)
     :user/email (:email user)}))

;; 리졸버 — user-id로 주문 목록을 가져옴
(pco/defresolver user-orders [{:keys [user-id]}]
  {::pco/output [:user/orders]}
  {:user/orders (db/find-orders-by-user user-id)})

(def env (pci/register [user-by-id user-orders]))

;; 클라이언트는 그래프 쿼리로 요청
(p.eql/process env
  {:user-id 42}
  [:user/name :user/email :user/orders])
;; => {:user/name "Min-yong" :user/email "..." :user/orders [...]}

Pathom이 알아서 두 리졸버를 호출하고 결과를 합친다. 클라이언트는 데이터 출처를 모른다.

왜 좋은가

  • 백엔드를 점진적으로 리팩토링할 수 있다. 리졸버 안쪽을 바꿔도 클라이언트 쿼리는 그대로.
  • N+1 문제를 Pathom이 자동으로 배치 처리.
  • GraphQL과 달리 스키마 정의가 코드와 일체화.

누가 쓰나 Fulcro 풀스택 프레임워크의 백엔드 표준. Nubank의 일부 마이크로서비스가 Pathom으로 데이터 집계 레이어를 구성한다.


7장 · Datomic Pro · Cloud — 시간을 데이터로

Datomic은 Rich Hickey 자신이 설계한 데이터베이스다. Cognitect가 만들었고, 2023년부터 Datomic Pro 라이선스가 무료가 되어 진입 장벽이 사라졌다. 2026년 시점에 Datomic은 두 가지 제품군이 있다.

  • Datomic Pro — 자체 호스팅, 무료. PostgreSQL/DynamoDB/Cassandra 등을 스토리지로 사용.
  • Datomic Cloud — AWS 위 서버리스 매니지드, 유료.

Datomic의 핵심 아이디어

  1. immutable — 데이터를 절대 덮어쓰지 않는다. 모든 변경이 append-only.
  2. bitemporal — 트랜잭션 시간(언제 기록됐는지)과 valid 시간(언제 사실이었는지)을 별도로 추적.
  3. EAV 모델 — entity-attribute-value 트리플. RDF와 비슷.
  4. 읽기와 쓰기의 분리 — peer/client가 인덱스를 로컬 메모리에 가져와 쿼리. transactor만 직렬화.
;; 스키마 정의
(def schema
  [{:db/ident :user/email
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one
    :db/unique :db.unique/identity}
   {:db/ident :user/name
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}])

(d/transact conn {:tx-data schema})

;; 데이터 삽입
(d/transact conn
  {:tx-data [{:user/email "min@example.com"
              :user/name "Min-yong Kim"}]})

;; Datalog 쿼리
(d/q '[:find ?name
       :in $ ?email
       :where
       [?u :user/email ?email]
       [?u :user/name ?name]]
     (d/db conn)
     "min@example.com")
;; => [["Min-yong Kim"]]

bitemporal — 시간 여행 쿼리

;; "2025년 12월 1일 시점의" DB로 같은 쿼리
(d/q '[:find ?name ...]
     (d/as-of (d/db conn) #inst "2025-12-01"))

;; 어떤 entity의 모든 변경 이력
(d/history (d/db conn))

왜 쓰나

  • 감사(audit) 요구사항이 강한 금융·의료 시스템에 적합.
  • 스키마 마이그레이션 없이 새 속성을 추가할 수 있음.
  • 읽기 캐시가 peer에 있어 read-heavy 워크로드에 강함.

누가 쓰나 Nubank의 거의 모든 백엔드 마이크로서비스가 Datomic을 쓴다(자체 인프라). 회계·법무·의료 도메인에서 점점 채택이 늘고 있다.

Datomic은 "DB가 함수형이어야 한다"는 Rich Hickey의 주장의 결정체다. 비싸지 않다, 무료다. 그러나 사고방식의 전환이 필요하다.


8장 · XTDB 2.0 — bitemporal + SQL-first

XTDB(예전 이름 Crux)는 영국 JUXT 팀이 만든 bitemporal 데이터베이스다. 2026년 시점에 XTDB 2.0이 안정 버전이며, 1.x와 비교해 큰 변화가 있다.

1.x → 2.0의 차이

  • 컬럼나 스토리지(Apache Arrow 기반)로 분석 쿼리 성능 대폭 향상
  • SQL을 1급 시민으로 — 더 이상 Datalog만 강요하지 않음
  • 객체 스토리지(S3)에 데이터를 저장 — 비용 절감
-- XTDB 2.0 — 표준 SQL로 시간 여행
SELECT name, email
FROM users
FOR VALID_TIME AS OF DATE '2025-12-01'
WHERE name LIKE 'Min%';

-- 트랜잭션 시간과 valid 시간을 모두 지정
SELECT *
FROM users
FOR SYSTEM_TIME AS OF TIMESTAMP '2026-01-15 10:00:00'
FOR VALID_TIME AS OF DATE '2025-12-01';

Clojure에서도 호출 가능.

(require '[xtdb.api :as xt])

(xt/q node
  '(from :users [name email]))

;; SQL도 동등
(xt/q node "SELECT name, email FROM users")

왜 XTDB인가 vs Datomic

  • XTDB는 SQL 호환이 강점. PostgreSQL 사용자가 갈아타기 쉽다.
  • Datomic은 Datalog 우선이며 더 깊은 그래프 쿼리에 강하다.
  • XTDB 2.0의 컬럼나 스토리지는 분석 워크로드(OLAP)에 강하다.
  • Datomic은 transactional 워크로드(OLTP)에 더 최적화.

Datalevin과 Datahike 임베디드/온디바이스 시나리오. Datalevin은 LMDB 기반 임베디드 Datalog DB. Datahike는 IPFS도 백엔드로 쓸 수 있는 분산 친화 Datomic-like DB. 모바일이나 Electron 앱에 묻어 쓰기 좋다.


9장 · next.jdbc · HoneySQL — 모던 SQL 스택

Datomic이나 XTDB가 모든 시나리오에 맞는 건 아니다. 기존 PostgreSQL·MySQL을 그대로 써야 할 때가 많다. 2026년 Clojure의 표준 JDBC 라이브러리는 next.jdbc이고, SQL DSL은 HoneySQL이다.

next.jdbc 기본

(require '[next.jdbc :as jdbc])

(def db {:dbtype "postgresql"
         :dbname "myapp"
         :user "postgres"
         :password "secret"})

;; 쿼리
(jdbc/execute! db ["SELECT id, name FROM users WHERE id = ?" 42])
;; => [{:users/id 42 :users/name "Min-yong"}]

;; 트랜잭션
(jdbc/with-transaction [tx db]
  (jdbc/execute! tx ["INSERT INTO users (name) VALUES (?)" "New User"])
  (jdbc/execute! tx ["INSERT INTO accounts (user_id, balance) VALUES (?, ?)"
                     42 0]))

next.jdbc는 clojure.java.jdbc의 후속이며, 더 빠르고 더 작은 API다. 결과를 자동으로 키워드 키 맵으로 변환한다.

HoneySQL — SQL을 데이터로

(require '[honey.sql :as sql])

(sql/format
  {:select [:id :name :email]
   :from [:users]
   :where [:and
           [:= :status "active"]
           [:> :age 18]]
   :order-by [[:created-at :desc]]
   :limit 10})
;; => ["SELECT id, name, email FROM users
;;      WHERE status = ? AND age > ? ORDER BY created_at DESC LIMIT ?"
;;     "active" 18 10]

EDN 맵으로 SQL을 표현한다. 동적으로 조건을 합치거나, 일부 절을 떼서 함수로 만들기 쉽다. ORM이 아니라 데이터 우선 SQL 생성기다.


10장 · Ring · Compojure · Reitit — HTTP 서버 3대장

Clojure 백엔드는 거의 모두 Ring을 베이스로 한다. Ring은 HTTP 요청/응답을 단순한 맵으로 표현하는 추상화다. 위에 여러 라우팅 라이브러리가 얹힌다.

Ring 기본 요청은 맵, 응답도 맵, 핸들러는 함수.

(defn handler [request]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body "Hello, world"})

;; jetty 서버로 실행
(require '[ring.adapter.jetty :as jetty])
(jetty/run-jetty handler {:port 3000})

미들웨어는 핸들러를 감싸는 고차 함수.

(defn wrap-logging [handler]
  (fn [request]
    (println "Request:" (:uri request))
    (handler request)))

(jetty/run-jetty (wrap-logging handler) {:port 3000})

Compojure — 고전 라우터

(require '[compojure.core :refer [defroutes GET POST]])

(defroutes app
  (GET "/" [] "Home")
  (GET "/users/:id" [id] (str "User " id))
  (POST "/users" req (create-user req)))

작은 앱에는 충분하지만, 큰 앱에서는 라우트 정의가 코드라 정적 분석이 어렵다.

Reitit — 데이터 우선 라우터

(require '[reitit.ring :as ring]
         '[reitit.coercion.malli :as rcm])

(def app
  (ring/ring-handler
    (ring/router
      [["/api"
        ["/users"
         {:get  {:handler list-users
                 :parameters {:query [:map [:limit int?]]}}
          :post {:handler create-user
                 :parameters {:body [:map [:name string?] [:email string?]]}}}]
        ["/users/:id"
         {:parameters {:path [:map [:id int?]]}
          :get {:handler get-user}}]]]
      {:data {:coercion rcm/coercion
              :middleware [...]}})))

라우트가 데이터다(벡터+맵). 미들웨어, 입력 검증(coercion), OpenAPI 스펙 생성을 자동화할 수 있다. 2026년 신규 API 프로젝트 ~60%가 Reitit를 택한다.

Pedestal Cognitect가 만든 대안. 인터셉터 체인 모델로 비동기·스트리밍을 1급으로 다룬다. Reitit보다 학습 곡선이 가파르지만, 복잡한 워크플로(예: SSE, 큰 파일 업로드)에 강하다.


11장 · Aleph · Manifold · core.async — 비동기와 스트림

Clojure의 동시성 모델은 세 축으로 나뉜다.

  1. core.async — Go 채널 스타일. CSP 모델.
  2. Manifold — 디퍼드(deferred)와 스트림. 더 함수형 친화.
  3. Aleph — Netty 위의 비동기 HTTP/TCP 서버. Manifold를 쓴다.

core.async

(require '[clojure.core.async :as async :refer [go chan <! >!]])

(let [c (chan 10)]
  (go (>! c "hello")
      (>! c "world"))
  (go (println (<! c))
      (println (<! c))))

go 블록은 가벼운 코루틴, <!/>!는 채널에서 받고 보내는 연산. JVM 위에서 Go 같은 코드가 돈다.

Manifold

(require '[manifold.deferred :as d]
         '[manifold.stream :as s])

;; deferred는 promise + future의 일반화
(def result (d/deferred))
(d/chain result inc inc inc)  ; 함수 체이닝
(d/success! result 1)          ; => 4

;; stream은 비동기 시퀀스
(def s (s/stream))
(s/consume #(println "got:" %) s)
(s/put! s 42)  ; => "got: 42" 출력

Aleph 서버

(require '[aleph.http :as http])

(defn handler [req]
  ;; deferred를 반환하면 Aleph가 비동기로 처리
  (d/future
    (Thread/sleep 100)
    {:status 200 :body "done"}))

(http/start-server handler {:port 3000})

Aleph는 Netty 위에 얹혀 있어 한 서버에서 수만 동시 연결을 다룬다. 웹소켓, SSE, gRPC도 자연스럽다.

core.async가 Go의 채널이라면, Manifold는 Scala의 Future + Akka Stream의 Clojure 표현이다. 둘은 보완 관계이며 한 앱에서 같이 써도 된다.


12장 · Spec · Malli · Schema — 검증의 세 갈래

Clojure는 동적 타입이지만, 데이터 형태(shape)를 검증할 도구가 풍부하다. 세 라이브러리가 경쟁한다.

clojure.spec — 공식 답

(require '[clojure.spec.alpha :as s])

(s/def :user/email (s/and string? #(re-matches #".+@.+" %)))
(s/def :user/age (s/and int? #(<= 0 % 150)))
(s/def :user/user (s/keys :req-un [:user/email :user/age]))

(s/valid? :user/user {:email "min@example.com" :age 30})
;; => true

(s/explain :user/user {:email "bad" :age 30})
;; => :email failed: re-matches predicate

s/keys로 맵 형태를 정의하고, s/and/s/or로 조합. Spec은 함수의 인자/반환값 명세도 지원한다.

(s/fdef calc-tax
  :args (s/cat :amount pos-int? :rate (s/and number? pos?))
  :ret pos-int?)

stest/instrument로 활성화하면 함수 호출 시 자동 검증.

Malli — 데이터 우선 + 빠름

(require '[malli.core :as m])

(def User
  [:map
   [:email [:re #".+@.+"]]
   [:age [:int {:min 0 :max 150}]]])

(m/validate User {:email "min@example.com" :age 30})
;; => true

(m/explain User {:email "bad" :age 30})
;; => {:errors [...]} 상세 에러

Malli는 스키마가 데이터(EDN) 라 직렬화·전송이 쉽고, Reitit의 입력 검증, OpenAPI 스펙 생성, 자동 문서화에 자연스럽게 연결된다. 2026년 신규 프로젝트의 다수가 Malli를 택한다.

Plumatic Schema — 클래식 가장 오래된 라이브러리. 매크로 기반이라 컴파일 타임 검증이 가능. 레거시 프로젝트에 많이 남아 있다.

어떻게 고르나

  • 공식 도구로 가고 싶다 → Spec
  • 데이터 우선 + Reitit·Malli 통합 → Malli
  • 레거시 호환 → Schema

13장 · Mount · Integrant · Component — DI/라이프사이클

큰 시스템은 시작 순서(DB 연결 → 캐시 → HTTP 서버 → 백그라운드 작업)와 종료 순서가 중요하다. Clojure에는 이를 위한 세 라이브러리가 있다.

Mount — 가장 단순

(require '[mount.core :as mount])

(mount/defstate db
  :start (open-connection "jdbc:...")
  :stop (close-connection db))

(mount/defstate server
  :start (start-server {:port 3000})
  :stop (stop-server server))

(mount/start)  ; 모두 시작
(mount/stop)   ; 역순으로 종료

전역 상태를 쓰지만 매우 단순하다. 작은 프로젝트에 적합.

Component — Stuart Sierra의 클래식

(defrecord Database [config conn]
  component/Lifecycle
  (start [this] (assoc this :conn (open-connection config)))
  (stop [this] (close-connection conn) (assoc this :conn nil)))

(def system
  (component/system-map
    :db (->Database db-config nil)
    :server (component/using (->Server {}) [:db])))

의존성을 명시적으로 선언한다. 테스트에서 컴포넌트를 교체하기 쉽다.

Integrant — 데이터 우선 Component

(require '[integrant.core :as ig])

(def config
  {:db/connection {:url "jdbc:..."}
   :server/jetty  {:db (ig/ref :db/connection) :port 3000}})

(defmethod ig/init-key :db/connection [_ {:keys [url]}]
  (open-connection url))

(defmethod ig/init-key :server/jetty [_ {:keys [db port]}]
  (start-server {:db db :port port}))

(def system (ig/init config))
(ig/halt! system)

설정이 EDN 데이터라 환경별 설정 파일로 분리 가능. Reitit와 자연스럽게 어울린다. 2026년 신규 프로젝트의 가장 흔한 선택.


14장 · 테스팅 — clojure.test부터 generative까지

clojure.test — 표준

(require '[clojure.test :refer [deftest is testing]])

(deftest user-creation-test
  (testing "valid input creates user"
    (is (= "Min-yong" (:name (create-user {:name "Min-yong"})))))
  (testing "missing email throws"
    (is (thrown? Exception (create-user {})))))

기본 내장. JUnit과 비슷한 느낌이지만 더 함수형.

Kaocha — 모던 러너 clojure.test 위에 얹는 러너. 컬러 출력, 워치 모드, 플러그인 시스템, JUnit XML 리포트.

clj -M:test  # 또는 bb test

tests.edn으로 설정. CI에서 결정적인 출력을 내기 좋다.

Eftest clojure.test 호환. 워치 모드와 병렬 실행에 강하다.

clojure.test.check — Property-based testing

(require '[clojure.test.check :as tc]
         '[clojure.test.check.generators :as gen]
         '[clojure.test.check.properties :as prop])

(def reverse-twice-is-identity
  (prop/for-all [v (gen/vector gen/int)]
    (= v (reverse (reverse v)))))

(tc/quick-check 100 reverse-twice-is-identity)
;; => 100개 임의 입력으로 검증

QuickCheck의 Clojure 포트. 입력을 무작위로 생성해 속성을 검증한다.

clojure.spec.test — Spec과 통합

(require '[clojure.spec.test.alpha :as stest])

(stest/check `calc-tax)
;; => spec fdef로 정의된 함수를 generative하게 테스트

Spec 명세가 있으면 자동으로 generative 테스트가 돈다.


15장 · 에디터 4파전 — Cursive · Calva · CIDER · Conjure

Clojure 개발은 REPL이 핵심이다. 코드를 파일로 저장하고 다시 시작하는 게 아니라, 실행 중인 REPL에 한 표현식씩 보내 즉시 평가한다. 그래서 에디터 선택이 다른 언어보다 더 결정적이다.

Cursive — IntelliJ IDEA 플러그인 가장 완성도 높은 상용 옵션. 코드 인텔리전스(자동완성, 리팩토링, 정적 분석)가 강력하다. 큰 프로젝트에서 정확한 navigation과 refactoring이 필요할 때 압도적. 개인 라이선스 연 99달러, 상용은 다른 요금. 무료 EAP 빌드도 있다.

Calva — VS Code 확장 무료, 오픈소스, 가장 많이 쓰는 에디터. REPL 통합, 패러디트(paredit) 편집, 인라인 평가 결과 표시, jack-in 자동화. VS Code 사용자라면 첫 선택. 2026년 Clojure 사용자의 ~45%가 Calva를 쓴다는 비공식 설문.

CIDER — Emacs 가장 오래되고 가장 강력. REPL 통합, 디버거, 트레이스, 매크로 단계별 확장 시각화까지 모두 1급. Emacs를 이미 쓰는 사람이라면 거의 디폴트.

Conjure — Neovim Neovim 사용자를 위한 답. tmux-friendly. lightweight하지만 모든 핵심 기능을 갖춤.

파일 → REPL 흐름 Cursive·Calva·CIDER 모두 같은 흐름이다. 파일을 열고, "이 폼을 REPL에서 평가" 키(Cmd-Enter, Cmd-Shift-Enter 등)를 누르면 표현식이 REPL에 전송된다. 함수를 수정하고 다시 평가하면 즉시 새 정의가 살아 있는 시스템에 반영된다. 서버를 재시작하지 않는다.

"REPL에 코드를 보내는 그 순간이 Clojure를 쓰는 가장 큰 이유다. 컴파일·실행·중단의 사이클이 없다. 코드는 항상 살아 있다." — Bruce Hauman, Figwheel 저자.


16장 · REPL 주도 개발 — 왜 LLM 시대에 가장 적합한가

REPL 주도 개발(REPL-driven development)은 Clojure 문화의 심장이다. 핵심 아이디어는 단순하다.

  1. REPL을 항상 띄워 둔다.
  2. 코드는 파일에 있지만, 실행은 REPL에서 한 표현식씩 한다.
  3. 결과를 보고, 코드를 수정하고, 다시 평가한다.
  4. 만족스러우면 그 코드를 파일에 두고 다음으로 넘어간다.

왜 LLM 시대에 더 빛나는가 LLM은 코드 블록을 생성한다. 사람은 그걸 검증해야 한다. 검증 방법은 두 가지.

  • 전통적 방법: 파일에 붙여넣고, 빌드/테스트를 돌리고, 결과를 본다. 사이클이 길다(수십 초 ~ 수 분).
  • REPL 방법: LLM이 생성한 표현식을 REPL에 바로 평가한다. 즉시 결과가 나온다. 잘못됐으면 다시 묻고, 다시 평가한다.

Clojure는 이 워크플로에 본질적으로 맞다. 데이터가 EDN으로 표현 가능하니 LLM이 생성한 데이터를 REPL에 그대로 붙여 평가할 수 있다. 매크로 시스템이 강해 LLM이 도메인 특화 코드를 짧게 표현할 수 있다.

실전 LLM + REPL 워크플로

;; LLM에게 "사용자 목록에서 30대 만 필터링하는 함수 작성"이라고 요청
;; LLM의 답을 REPL에 평가:
(defn users-in-30s [users]
  (filter #(<= 30 (:age %) 39) users))

;; 즉시 테스트
(users-in-30s [{:name "A" :age 25}
               {:name "B" :age 35}
               {:name "C" :age 45}])
;; => ({:name "B" :age 35})

;; 잘 도네. 파일에 저장.

긴 빌드 사이클 없이 LLM 응답을 바로 검증할 수 있다. 2026년 Cursive·Calva 모두 LLM 응답을 REPL에 바로 보내는 단축키를 지원한다.


17장 · GraalVM Native Image — Clojure를 네이티브 바이너리로

GraalVM은 JVM 바이트코드를 ahead-of-time(AOT) 컴파일해 네이티브 실행 파일을 만든다. Clojure 프로그램을 GraalVM Native Image로 컴파일하면 시작 속도가 20ms로 떨어진다(JVM의 12초 vs).

언제 유용한가

  • CLI 도구 (Babashka가 정확히 이 카테고리)
  • AWS Lambda 같은 cold-start가 중요한 서버리스
  • 작은 마이크로서비스 (예: 단일 헬스체크 엔드포인트)

한계

  • 리플렉션, 동적 클래스 로딩에 제약이 있다. Clojure는 동적 언어라 일부 패턴이 안 된다.
  • 빌드 시간이 매우 길다(분 단위).
  • 메모리 풋프린트는 작지만, 피크 성능은 JIT보다 낮을 수 있다.

실전 예 Babashka 자체가 가장 큰 성공 사례. bb 바이너리는 GraalVM으로 컴파일된 약 80MB의 정적 바이너리. 시작 속도 ~20ms, 메모리 ~30MB. Python보다 가볍게 돈다.

자기 앱을 native-image로 만들 때는 org.clj-easy/graal-build-time 같은 헬퍼 라이브러리와 clj.native-image 같은 빌드 도구를 쓴다. JVM 호환성 옵션(--initialize-at-build-time 등)을 잘 설정해야 한다.


18장 · Nubank 사례 — 1억 사용자를 Clojure로

Nubank는 Clojure 세계 최대의 프로덕션 사례다. 브라질 발 디지털 은행으로 2026년 시점에 1억 1,000만 고객, 마이크로서비스 5,000개 이상, 일 트랜잭션 수십억 건을 처리한다. 그들의 백엔드는 거의 전체가 Clojure다.

왜 Clojure를 택했나 Nubank의 공동창업자이자 CTO인 Edward Wible의 설명(공개된 강연 다수에서). 세 가지 이유.

  1. 함수형 + 불변 데이터 — 금융 데이터는 절대 임의 수정이 일어나면 안 된다. immutable이 자연스럽게 그 안전망을 준다.
  2. Datomic — 모든 거래 이력을 bitemporal로 유지해야 한다. Datomic의 모델이 정확히 맞다.
  3. REPL 주도 개발 — 프로덕션 디버깅에 REPL을 띄워 라이브 데이터를 조사한다. 거래 사고가 났을 때 즉각 진단 가능.

아키텍처 개요

  • 모든 마이크로서비스가 Clojure (일부 Kotlin/Go도 있음)
  • Datomic이 메인 DB (자체 Pro 라이선스, AWS DynamoDB 백엔드)
  • Kafka로 마이크로서비스 간 이벤트 스트림
  • Pedestal/Aleph 기반 HTTP 서버
  • Schema(레거시)와 Malli(신규)로 데이터 검증
  • 자체 개발한 Pathom-like 그래프 쿼리 레이어

팀 운영 ~2,000명의 엔지니어가 Clojure를 쓴다. 신규 채용 시 Clojure 경험은 필수가 아니다 — 자체 트레이닝 부트캠프로 가르친다. 함수형 사고가 있으면 빠르게 적응한다는 정책.

성능

  • p99 응답 시간: 50ms 미만 (대부분 엔드포인트)
  • 가용성: 99.99% 이상
  • 한 마이크로서비스당 평균: 인스턴스 ~5개, 메모리 ~512MB

"Clojure를 택한 게 사업에 가장 좋은 결정 중 하나였다. 단순함이 우리를 빠르게 했다." — Edward Wible, Nubank CTO.


19장 · 한국·일본 커뮤니티 — 어디까지 왔나

Clojure Korea 서울 중심으로 활동하는 커뮤니티. Slack 채널 clojure-kr, 정기 밋업, 페어 프로그래밍 세션. 김민용(Mun-yong Kim) 등 1세대 개발자들이 적극적으로 활동한다. 카카오·네이버 내부에서도 일부 팀이 Clojure를 쓴다(자세한 공개 자료는 적지만). 한국어 자료로는 위키북·인사이트의 번역서, 그리고 GitHub 한국어 튜토리얼이 있다.

Clojure Tokyo / Clj-jp 일본 커뮤니티는 한국보다 활동이 더 활발하다. 도쿄 정기 밋업, 후쿠오카·오사카 지부, 연 1회 컨퍼런스 Clj-jp Conf. Drip(주류), Cookpad(요리 레시피), Recruit 등 일부 일본 기업이 프로덕션에서 쓴다. 일본어 학습 자료가 풍부하다.

아시아 컨퍼런스

  • Clojure/conj — 미국, 가장 큰 컨퍼런스 (연 1회)
  • Clojure/north — 캐나다
  • re:Clojure — 영국
  • EuroClojure — 유럽
  • Clj-jp Conf — 일본

2026년에는 한국에서도 작은 규모의 Clojure 컨퍼런스가 부활하려는 움직임이 있다.


20장 · 2026년에 시작하는 사람의 스택 추천

배경별로 정리한다.

Java/Kotlin 출신

  • Clojure 1.12 + Leiningen → 익숙한 빌드 도구로 시작
  • IntelliJ IDEA + Cursive
  • Ring + Compojure(작은 앱) 또는 Reitit(중대형)
  • PostgreSQL + next.jdbc + HoneySQL
  • 첫 책: "Programming Clojure (4th edition)"

JavaScript/TypeScript 출신

  • ClojureScript + shadow-cljs
  • VS Code + Calva
  • Reagent + re-frame(검증된 안정성) 또는 UIx 2(모던)
  • npm 패키지를 그대로 가져다 쓰는 데서 시작
  • 첫 책: "Learn ClojureScript" (무료, 온라인)

Python/Ruby 출신

  • Babashka로 셸 스크립트부터 시작
  • VS Code + Calva
  • Datomic Pro 또는 SQLite + next.jdbc
  • REPL 주도 개발 학습이 가장 큰 mind shift
  • 첫 자료: 공식 사이트 "Getting Started"

Lisp 경험자 (Scheme, CL)

  • 학습이 매우 빠르다
  • Cursive 또는 Emacs+CIDER
  • 함수형이 더 강조된다는 점만 적응
  • 매크로 시스템은 Common Lisp과 비슷

공통 학습 경로

  1. REPL 켜고 한 줄씩 실험lein repl 또는 clj
  2. 데이터 다루기 연습map, filter, reduce, into, update-in, select-keys
  3. 상태 관리atom, ref, agent의 차이
  4. 시퀀스 추상 — lazy seq, transducer
  5. 매크로 — 마지막에

"Clojure를 일주일 만에 배웠다"고 말하는 사람이 있다. 사실 그게 가능하다. 그러나 그 후 6개월이 진짜 시작이다. 함수형 사고는 시간이 필요하다.


21장 · 자주 받는 의문에 답한다

Q: 동적 타입이라 런타임에 깨지지 않나? A: 부분적으로 맞다. 그러나 Clojure는 데이터 형태를 EDN과 Spec/Malli로 명세화한다. 함수 경계에서 검증하고, 내부는 동적으로 다룬다. 큰 시스템에서도 잘 굴러간다 — Nubank가 증명한다.

Q: 인재 풀이 작지 않나? A: 작다. 그러나 남는 인재가 강하다. Clojure 채용은 함수형 사고를 가진 사람을 거른다. 평균적으로 더 시니어한 팀이 된다는 보고가 일관된다. Nubank 채용 데이터: 이직률이 다른 핀테크 평균의 절반.

Q: 채용이 어렵지 않나? A: 두 가지 답. (1) 다른 언어 출신을 채용해 가르치는 게 정답. Clojure는 빠르게 배울 수 있다. (2) Clojure를 쓴다는 사실 자체가 좋은 엔지니어를 끌어들이는 자석이 된다.

Q: 성능은? A: JVM 위에서 도는 만큼 JIT 컴파일이 된 코드는 자바 수준. 핫 패스에서 박싱 회피, 타입 힌트 등 최적화 가능. Nubank의 p99 50ms는 일반 자바·Go 백엔드와 동등하거나 그 이상.

Q: 학습 곡선? A: 가파른 부분이 두 군데. (1) 괄호와 prefix 표기법 적응 — 보통 1주일. (2) 함수형 사고 — 평균 3개월. 그 뒤로는 평탄하다.

Q: 자바 라이브러리 호출은? A: 1급 시민. (.method obj arg) 또는 1.12부터 Class/.method 형태. 자바 라이브러리 거의 다 쓸 수 있다. JVM 호스트의 가장 큰 장점.

Q: Clojure를 못 쓰는 경우는? A: 세 가지. (1) GC 일시정지를 절대 못 견디는 hard real-time. (2) 메모리 풋프린트가 매우 작아야 하는 임베디드 (단, Babashka로 일부 해결). (3) 팀 전체가 함수형에 거부감이 있을 때.


22장 · 2026년 이후의 방향

예상되는 흐름

  1. AI/LLM 통합 강화 — REPL 주도 개발과 LLM의 궁합이 좋아 IDE 통합이 깊어진다. Cursive·Calva가 Claude·Cursor 같은 도구와 더 가까워진다.
  2. ClojureScript의 부활 — UIx 2와 React Server Components의 만남, Bun·Deno 같은 새 런타임 지원이 작업 중.
  3. Babashka의 영역 확장 — 셸 스크립트 → CLI 도구 → 작은 서버까지. nbb·squint와 함께 점점 영역이 넓어진다.
  4. Datomic vs XTDB의 경쟁 — bitemporal DB 시장이 커지면서 두 진영이 발전을 가속.
  5. GraalVM Native Image의 안정화 — 더 많은 Clojure 라이브러리가 native-image 호환을 보장.
  6. WebAssembly 컴파일 — ClojureScript → WASM 실험이 진행 중. 브라우저 외 사용 가능성 열림.

위험 요소

  • Rich Hickey의 후계 — Hickey는 2022년 Nubank에서 은퇴했다. Cognitect 팀이 잘 이어받고 있지만, 한 사람의 비전이 사라진 후 장기적 일관성이 시험대에 오른다.
  • Datomic의 미래 — Cognitect가 Nubank에 인수된 후, Datomic의 오픈소스화가 어디까지 갈지 불투명.
  • 다른 함수형 언어와의 경쟁 — Elixir·Gleam·Roc 등이 새로 떠오른다. Clojure는 어떻게 차별화를 유지할 것인가.

낙관적 시나리오 Nubank의 성공이 다른 핀테크·바이오·헬스 도메인에 퍼진다. 한국·일본 대기업에서도 점진 채택. ClojureScript의 React 통합이 더 매끄러워져 프런트엔드 시장에서 의미 있는 점유율 확보.


23장 · 결론 — Clojure가 살아남은 이유

20년 가까이 일관성을 지킨 언어는 많지 않다. Rich Hickey의 원칙 — "단순함은 쉬움보다 중요하다(simple is better than easy)" — 이 Clojure의 모든 결정에 깔려 있다. 그 결과 Clojure는 트렌드를 따르지 않고 자기 길을 갔다.

그게 살아남은 이유다. 핀테크, 의료, 회계, 컴플라이언스 — 정확성이 속도보다 중요한 도메인에서 Clojure는 절대적이다. Nubank가 1억 사용자를 굴린다는 사실은 우연이 아니다.

2026년에 Clojure를 시작하는 사람에게 줄 한 마디.

빠르게 배우려고 하지 마라. REPL을 띄워 두고, 한 표현식씩, 천천히 익혀라. Clojure는 한 번에 배우는 게 아니라, 한 표현식씩 길러지는 언어다. 6개월 뒤에는 다른 언어로 못 돌아간다.

행운을 빈다. REPL을 켜고 시작하자.


References

  1. Clojure 공식 사이트 — https://clojure.org
  2. Clojure 1.12 Release Notes — https://github.com/clojure/clojure/blob/master/changes.md
  3. Rich Hickey, "Simple Made Easy" — https://www.youtube.com/watch?v=SxdOUGdseq4
  4. Rich Hickey, "Hammock Driven Development" — https://www.youtube.com/watch?v=f84n5oFoZBc
  5. Babashka 공식 — https://babashka.org
  6. Michiel Borkent, "Babashka: A native Clojure interpreter for scripting" — https://blog.michielborkent.nl
  7. ClojureScript 공식 — https://clojurescript.org
  8. shadow-cljs 공식 — https://github.com/thheller/shadow-cljs
  9. re-frame 공식 — https://day8.github.io/re-frame
  10. Reagent 공식 — https://reagent-project.github.io
  11. Helix 공식 — https://github.com/lilactown/helix
  12. UIx 2 공식 — https://github.com/pitch-io/uix
  13. Pathom 3 공식 — https://pathom3.wsscode.com
  14. Datomic 공식 — https://www.datomic.com
  15. XTDB 2.0 공식 — https://xtdb.com
  16. next.jdbc 공식 — https://github.com/seancorfield/next-jdbc
  17. HoneySQL 공식 — https://github.com/seancorfield/honeysql
  18. Reitit 공식 — https://github.com/metosin/reitit
  19. Pedestal 공식 — https://pedestal.io
  20. Aleph 공식 — https://github.com/clj-commons/aleph
  21. Manifold 공식 — https://github.com/clj-commons/manifold
  22. core.async 공식 — https://github.com/clojure/core.async
  23. clojure.spec 공식 — https://clojure.org/about/spec
  24. Malli 공식 — https://github.com/metosin/malli
  25. Integrant 공식 — https://github.com/weavejester/integrant
  26. Kaocha 공식 — https://github.com/lambdaisland/kaocha
  27. clojure.test.check 공식 — https://github.com/clojure/test.check
  28. Cursive 공식 — https://cursive-ide.com
  29. Calva 공식 — https://calva.io
  30. CIDER 공식 — https://docs.cider.mx
  31. Nubank Engineering Blog — https://building.nubank.com.br/tag/clojure
  32. Edward Wible, "Why Clojure?" — https://www.youtube.com/results?search_query=edward+wible+nubank+clojure
  33. Clojure 2024 State of Clojure Survey — https://clojure.org/news/2024/05/01/state-of-clojure-2024
  34. Clojure Korea Slack — https://clojurians.slack.com (#clojure-kr 채널)
  35. Clj-jp 공식 — https://clj-jp.org
  36. GraalVM Native Image — https://www.graalvm.org/native-image
  37. clj.native-image — https://github.com/taylorwood/clj.native-image
  38. Programming Clojure (4th ed) — https://pragprog.com/titles/shcloj4/programming-clojure-fourth-edition
  39. Learn ClojureScript (무료 책) — https://www.learn-clojurescript.com
  40. ClojureVerse 커뮤니티 포럼 — https://clojureverse.org