之前在「我的 Clojure 學習之路」一文,我分析了自己過去學習的五個階段:
1. Before knowing Clojure
2. Clojure Basic
3. Tried a lot of libraries
4. Selected Libraries
5. Level up by diving down
而在第五個階段,其實有一個很大的挑戰:「如果要 diving down 的話,要選什麼函式庫來 diving down ?」這個問題,透過 LLM 的協助,我整理出了以下的清單。這八個函式庫有以下的特性:
(a) 它們非常常用。如果你開發 web application 沒有用到它,八成是因為你用了替代方案。那你要不要質疑一下你的替代方案?
(b) 它們的設計根本就是經典。
很遺憾的事情是,我本人至今也還沒有研究完畢。我的學習過程一直沒有一套有系統的教材,是在前進之中思考合理的教材。
總之,清單如下:
1. `weavejester/integrant`:
* 角色: 應用程式生命週期管理、依賴注入 (DI)。
* 啟發性: 教你如何將整個系統看作是資料。你用一個 map 來描述系統的所有元件(資料庫連線池、Web 伺服器、設定)以及它們之間的依賴關係。integrant 負責根據這個「藍圖」來啟動和關閉所有東西。這是「資料導向程式設計」在宏觀架構層面的終極體現。
2. `juxt/aero`:
* 角色: 設定管理。
* 啟發性: 教你如何讓設定檔本身也變得可程式化。透過 EDN 的標籤 (#env, #ref),你可以建立出動態、可組合、且不會洩漏密碼的設定檔。它完美地展示了利用 Clojure Reader 的能力來解決一個普遍存在的問題。
3. `ring-clojure/ring`:
* 角色: HTTP 抽象層的基石。
* 啟發性: Clojure 哲學的化身。它將複雜的 HTTP 請求/回應簡化為兩個 map,將橫切關注點(如日誌、Session)抽象為 middleware(高階函式)。研究 Ring,你就能理解組合性(composability) 的力量,以及如何用簡單的資料結構來為複雜的系統建立模型。
4. `metosin/reitit`:
* 角色: 路由 (Routing)。
* 啟發性: 教你如何將路由表也視為資料。你用一個 vector of vectors 來定義整個 API 的端點、HTTP 方法、處理器以及中介軟體。這種資料導向的方法不僅性能極高,而且讓路由的組合、生成和內省 (introspection) 變得輕而易舉。它完美地展示了如何用資料結構來取代複雜的 DSL 或巨集。
5. `metosin/malli`:
* 角色: 資料規格定義、驗證與轉換 (Data Schema, Validation & Coercion)。
* 啟發性: 教你如何用資料來描述資料的形狀。malli 讓你用 Clojure 的資料結構來定義你系統中所有資料的規格。這份單一的「規格資料」可以被多種方式使用:驗證 API 輸入、從字串自動轉換為 int 或 uuid、產生 OpenAPI/Swagger 文件、甚至進行生成式測試。它是一個典型的「一份定義,多種用途」的範例。
6. `buddy`:
* 角色: 身份驗證與授權。
* 啟發性: `protocol` 和策略模式 (Strategy Pattern)
的最佳教材。它定義了一個抽象的驗證協議,然後允許你插入任何具體的驗證策略(Session, JWT Token 等)。它完美地展示了如何設計一個可擴展、可插拔的系統,將「做什麼」與「如何做」徹底分離。
7. `seancorfield/honeysql`:
* 角色: SQL 查詢產生器。
* 啟發性: 再次展示了「將程式碼表示為資料」的思想。你不是在拼接字串,而是在建構描述 SQL 查詢的 Clojure map 和 vector。這使得動態產生複雜查詢變得極其安全和容易組合,徹底消除了 SQL 注入的風險。
8. `seancorfield/next-jdbc`:
* 角色: 資料庫存取。
* 啟發性: 教你如何為 Java API 建立一個更符合 Clojure 習慣的介面卡 (Adapter)。它透過 protocol (ReadableColumn, SettableParameter) 讓你可以擴展它,使其能處理自訂的資料類型。同時,它的函數式、基於 Reducer 的資料處理方式也極具啟發性,展示了如何將 I/O 操作與純粹的資料轉換優雅地結合起來。