Appendices: Projects, Interview Questions, Cheat Sheet & Study Plan

Capstone projects, interview questions, a Clojure cheat sheet, Clojure for developers coming from other languages, and resources with a study plan.

Appendix A: Capstone Projects

Beginner: Word Frequency CLI. slurp, re-seq, frequencies, sorting, tools.cli arguments, an uberjar build.

Beginner: To-Do App in the REPL. An atom holding a map, pure update functions, EDN persistence with spit/edn/read-string.

Intermediate: Bank Simulator. Refs and STM transfers, agents for audit logging, property-based tests for balance invariants.

Intermediate: Data Pipeline. Read a large CSV, transform with transducers, aggregate with group-by/reduce, write JSON; compare performance with lazy seqs.

Intermediate: Concurrent Web Crawler. core.async channels, worker pools with pipeline-blocking, timeouts, and rate limiting.

Intermediate: Shape Library. Protocols and records vs multimethods with hierarchies; benchmark both with criterium.

Advanced: REST API. Reitit + Malli coercion, next.jdbc + HoneySQL + PostgreSQL, Integrant system, migrations, tests, a Dockerized uberjar.

Advanced: Real-Time Chat. http-kit or Aleph WebSockets, core.async pub/sub, a re-frame frontend in ClojureScript.

Advanced: Datalog App. A Datomic Local or XTDB app with history queries and time travel.

Advanced: DSL with Macros. A validation or state-machine DSL implemented with macros, specced with clojure.spec, and fully tested.

Scripting: Dev-Ops Toolkit in Babashka. Tasks for builds, deployments, log analysis, and API calls.

Open Source: Publish a Library. A documented library with tests, clj-kondo config, CI, and a Clojars release.

Appendix B: Interview Questions

What is Clojure, and what are its core design principles?

What are persistent data structures? How does structural sharing work?

Explain truthiness in Clojure (nil, false).

Lists vs vectors: when do you use each? How does conj behave on each?

What are keywords, and why are they used as map keys? Why are maps and keywords functions?

def vs let vs defn vs defonce?

Explain destructuring (sequential and associative) with examples.

What is the sequence abstraction? What does seq return for an empty collection?

What does lazy evaluation mean in Clojure? What are chunked sequences? What are the pitfalls?

loop/recur vs plain recursion? What does trampoline do?

Explain ->, ->>, as->, some->, and cond->.

What are transducers, and why are they useful?

map vs mapv vs keep vs mapcat?

How do namespaces work? require, :as, :refer, import?

How do you handle errors idiomatically? What is ex-info?

What is EDN? Why should you use clojure.edn/read-string instead of read-string?

Explain deps.edn aliases and the -M, -X, and -T modes.

State and Concurrency Compare atoms, refs, agents, and vars.

Why must functions passed to swap! be pure?

How does STM work? What do alter, commute, and ensure do?

Future vs promise vs delay?

What is core.async? Explain channels, go blocks, >! vs >!!, and alts!.

Why shouldn't you block inside a go block?

Polymorphism, Interop and Macros Protocols vs multimethods: when do you use each?

defrecord vs deftype vs reify vs plain maps?

How do you call Java from Clojure? What are type hints and reflection warnings?

How do macros work? What are syntax-quote, unquote, and auto-gensyms?

When should you write a macro?

What is clojure.spec used for? How does it compare to Malli?

What is REPL-driven development?

How do you test Clojure code? What is property-based testing?

How do you optimize Clojure performance?

How do you structure a Clojure web application (Ring, middleware, routing, system management)?

What is ClojureScript? How does code sharing with .cljc work?

What is Babashka, and when would you use it?

Implement word frequency counting and return the top 10 words.

Flatten a nested map into dotted-path keys ({:a {:b 1}} → {"a.b" 1}).

Implement my-map and my-filter with reduce and with lazy-seq.

Write a transducer that removes consecutive duplicates.

Write a thread-safe counter service with an atom and validators.

Write a macro with-retry that retries a body N times on exception.

Group a list of transactions by month and compute totals.

Implement a core.async pipeline that processes jobs with three workers.

Appendix C: Clojure Cheat Sheet

;; ===== Definitions =====
(def x 1) (defn f [a] a) (defn- priv []) (defonce s (atom {})) (declare g)
(let [a 1 {:keys [b]} m [c & more] v] ...) (fn [x] x) #(* % 2)

;; ===== Collections =====
[1 2] '(1 2) {:a 1} #{1 2} (conj c x) (assoc m :k v) (dissoc m :k) (update m :k f)
(get m :k default) (get-in m [:a :b]) (assoc-in m [:a :b] v) (update-in m [:a] f) (merge m1 m2)
(keys m) (vals m) (select-keys m [:a]) (contains? c k) (count c) (into [] xs) (vec xs) (set xs)

;; ===== Sequences =====
(map f c) (filter p c) (remove p c) (reduce f init c) (keep f c) (mapcat f c) (some p c) (every? p c)
(first c) (rest c) (take n c) (drop n c) (sort-by f c) (group-by f c) (frequencies c) (partition n c)
(range n) (repeat x) (iterate f x) (cycle c) (distinct c) (concat a b) (for [x c :when (p x)] x)

;; ===== Control =====
(if c a b) (when c ...) (cond a x :else y) (case v :a 1 2) (if-let [x e] a b) (when-let [x e] ...)
(do ...) (loop [i 0] (recur (inc i))) (doseq [x c] ...) (dotimes [i n] ...)

;; ===== Threading =====
(-> x f g) (->> c (map f) (filter p)) (as-> x $ (f $ 1)) (some-> x :a :b) (cond-> m c (assoc :k v))

;; ===== State =====
(atom v) @a (swap! a f) (reset! a v) (ref v) (dosync (alte
…
clj   clj -M:dev   clj -M -m my.core   clj -X:test   clj -T:build uber   clj -Stree   bb tasks   clj-kondo --lint src

Appendix D: Clojure for Other Developers

(f x) / (.f obj x) (let [x 1]...) / (def x 1) lambda x: x*2 #(* % 2) / (fn [x] (* x 2)) for x in xs:

doseq, map, reduce, loop/recur Maps + functions; records + protocols Optional, null checks nil punning, some->, fnil Mutable by default

Immutable by default; atoms for state try/catch, ex-info with data deps.edn (Maven + git deps), Clojars Key gotchas:

Collections are immutable: (conj v x) returns a new vector; v is unchanged.

map/filter return lazy seqs; use mapv/filterv/into for concrete collections, and don't rely on side effects in lazy code.

Only nil and false are falsey.

= compares by value, including across collection types ((= [1 2] '(1 2)) is true), but (= 1 1.0) is false.

Parentheses mean "call": (x) calls x.

Long arithmetic throws on overflow (use +', *' or bigints for promotion).

Appendix E: Resources and Study Plan

clojure.org (reference, guides, rationale), clojure.org/api/cheatsheet, ClojureDocs (community examples), cljdoc.org (library docs), Clojars, ask.clojure.org

Rich Hickey's talks: *Simple Made Easy*, *Are We There Yet?*, *The Value of Values*, *Hammock Driven Development*, *Effective Programs*, *Spec-ulation*, *Maybe Not*

*Clojure for the Brave and True* (Daniel Higginbotham): free online, beginner-friendly *Getting Clojure* (Russ Olsen)

*Programming Clojure*, 4th ed. (Miller, Halloway, Bedra) *The Joy of Clojure* (Fogus & Houser) *Clojure Applied* (Vandgrift & Miller) *Elements of Clojure* (Zachary Tellman)

*Web Development with Clojure* (Sotnikov & Brown) *Data-Oriented Programming* (Yehonathan Sharvit)

*Grokking Simplicity* (Eric Normand): functional thinking with JavaScript examples, by a Clojurist

*Living Clojure* (Carin Meier), *Clojure Cookbook* Clojurians Slack, Clojureverse, r/Clojure, the Clojure Discord, Clojure/conj and Clojure/north conferences, re:Clojure, Heart of Clojure, Scicloj, *Clojure Stream* podcasts, Exercism, and the Clojure Koans 12-Week Study Plan Setup, REPL, syntax, scalar types

Collections, definitions, control flow, functions Destructuring, seqs, core functions, laziness

Recursion, threading macros, nested data, transducers Namespaces, deps.edn, errors, strings and I/O, data formats

State model, atoms, refs/STM, agents and vars Futures, promises, delays, virtual threads, core.async

Multimethods, protocols, records/types, Java interop Macros, clojure.spec, Malli

Testing, property-based tests, REPL workflow, performance Web, databases, system architecture, ClojureScript 43–46 + Capstone

Babashka, data science, deployment, internals, best practices

Final tip: Live in the REPL, think in data, and keep functions pure. Master immutable collections, the sequence library, destructuring, and atoms, then add protocols, core.async, and macros as needed. Watch *Simple Made Easy*, build something small every week, and you'll find Clojure makes complex systems feel surprisingly simple. Happy hacking! 🟢🔵