필사 모드: 모던 Clojure 2026 완벽 가이드 — Clojure 1.12 · Babashka · ClojureScript · shadow-cljs · Datomic · XTDB · re-frame 심층 분석
한국어프롤로그 — 왜 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.edn`과 `tools.deps`가 표준이 됐고, ClojureScript는 shadow-cljs를 통해 npm 생태계를 통째로 흡수했다. **Babashka**는 GraalVM 네이티브 이미지로 컴파일되어 시작 속도가 ~20ms — Python보다 빠르다. 셸 스크립트 시장에서 Bash와 Python을 동시에 위협한다.
2026년 5월, Clojure 1.12가 안정화되면서 **qualified method invocation** 같은 자바 상호운용성 개선이 들어왔고, `partial`과 `loop`가 더 똑똑해졌다. 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.edn`과 `tools.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로 작성한다. `Make`나 `package.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의 1~2초 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
현재 단락 (1/669)
2026년 5월, 누군가 "요즘 Lisp을 쓰는 사람이 있나?"라고 묻는다면, 답은 명확하다. **있다, 그것도 아주 많다**. 브라질의 Nubank는 1억 1,000만 명의 고객...