These pages cover the “small patterns” that give Clojure code its character: how to structure local bindings, thread data through transformations, use laziness intentionally, and keep functions compact without becoming cryptic. They are the kinds of habits that do not look dramatic in isolation but compound into a much better codebase.
If the functional-principles section gives you the why, this section gives you the day-to-day how.
- Threading Macros for Readable Clojure Pipelines
Learn when to use `->`, `->>`, `some->`, `cond->`, and `as->` so Clojure pipelines stay readable and match function argument shape.
- Local Bindings with `let` and `letfn`
Learn when `let` clarifies data flow, when `letfn` is appropriate for local helper functions, and how to avoid turning local bindings into clutter.
- Destructuring in Function Arguments
Learn how vector and map destructuring make Clojure functions more expressive, and where too much destructuring starts to hurt readability.
- Choosing `cond`, `case`, and `cond->` Well
Learn the real differences between `cond`, `case`, and `cond->`, and how to choose the right one for branching versus conditional transformation.
- Higher-Order Functions and Function Composition
Learn why higher-order functions are central to idiomatic Clojure, how they support composition and data-first design, and when passing behavior explicitly is better than adding more abstraction.
- Lazy Evaluation and Infinite Sequences
Learn how Clojure lazy sequences defer work, where infinite sequences are useful, and how to avoid head retention, chunking surprises, and accidental over-realization.
- Recursion with `recur`
Learn how `recur` makes specific recursive shapes stack-safe in Clojure, and why it is not the same thing as general automatic tail-call optimization.
- Memoization for Performance
Learn when Clojure memoization speeds up repeated work, when the built-in cache is the wrong tool, and how to avoid common traps with recursive and side-effecting functions.
- Namespaces and Modular Design in Clojure
Learn how namespaces create modular boundaries in Clojure, and how `require`, aliases, and clear file layout keep larger systems understandable.
- Protocols for Polymorphism in Clojure
Learn when protocols are the right polymorphism tool in Clojure, how they differ from multimethods and records alone, and how to extend them safely.
- Constructing DSLs in Clojure
Learn when Clojure is a good fit for internal DSLs, why data-driven designs usually beat macro-heavy syntax, and how to build domain-specific layers that remain readable and maintainable.
- Handling State with Atoms, Refs, and Agents
Learn how to choose between atoms, refs, and agents by the coordination and timing guarantees your Clojure state actually needs.
- Keywords and Symbols in Clojure
Learn the real semantic difference between keywords and symbols, and why one behaves like data while the other usually names or resolves code.
- Data-Oriented Programming in Clojure
Learn why Clojure leans toward plain immutable data plus separate functions, and where that model is stronger or weaker than object-heavy designs.
- The Component Pattern for System Construction
Learn how the Component pattern manages lifecycle and dependencies for stateful Clojure systems, and when the pattern helps more than it hurts.
- Multimethods with `defmulti` and `defmethod`
Learn when Clojure multimethods are better than protocols or plain conditionals, and how dispatch values, hierarchies, defaults, and prefer-method shape flexible runtime polymorphism.
- Persistent Data Structures and Structural Sharing
Learn what “persistent” means in Clojure, how structural sharing enables efficient immutable updates, and why persistent collections matter for concurrency, reasoning, and everyday code design.
- Using Clojure Spec for Data Validation
Learn where Clojure Spec is strongest for describing and checking data boundaries, and where a lighter validation approach may be clearer.
- Anonymous Functions with `fn` and `#()`
Learn when `fn`, `#()`, `partial`, or a named helper is the clearest choice for higher-order Clojure code.
- REPL-Driven Development in Clojure
Learn how to use the REPL as a serious development loop in Clojure for exploration, refactoring, debugging, and system inspection.
- Specter for Navigating and Transforming Data
Learn when Specter is better than get-in and update-in for complex nested data transformations, and how navigators, select, transform, and setval fit idiomatic Clojure data work.
- Using `partial`, `comp`, and `juxt`
Learn when Clojure composition helpers improve clarity, when thread macros are a better fit, and how `partial`, `comp`, and `juxt` solve different function-shaping problems.
- `reduce-kv`, `into`, and Collection Helpers
Learn when `reduce-kv`, `into`, `group-by`, `frequencies`, and related helpers make collection code simpler, faster, and more idiomatic.