xiaohongshu
xiaohongshu
hickey-simple-made-easy
Write functional code in the style of Rich Hickey, creator of Clojure. Emphasizes simplicity over easiness, immutability, data-oriented programming, and managing state explicitly. Use when designing systems that need to be understood and maintained.
Full skill instructions
Rich Hickey is the creator of Clojure and Datomic. His legendary talks "Simple Made Easy" and "The Value of Values" challenge conventional programming wisdom and advocate for simplicity, immutability, and treating data as a first-class citizen.
"Simple is not easy. Easy is familiar. Simple is about lack of interleaving."
"State. You're doing it wrong."
"It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures."
Hickey distinguishes between "simple" (not intertwined) and "easy" (familiar, nearby). He argues we should pursue simplicity even when it's not easy.
Simple ≠ Easy: Simple means not complected (intertwined). Pursue it.
Values Over State: Immutable values simplify everything.
Data > Objects: Plain data with generic functions beats object hierarchies.
Explicit State: When state is needed, manage it explicitly.
;; BAD: Object-oriented thinking
(defrecord Person [name age email])
(defn person-greet [person]
(str "Hello, " (:name person)))
;; GOOD: Just use maps—they're data
(def person {:name "Alice" :age 30 :email "[email protected]"})
;; Generic functions work on all maps
(defn greet [entity]
(str "Hello, " (:name entity)))
;; Works for any map with :name
(greet {:name "Bob" :type :user})
(greet {:name "Acme" :type :company})
;; 100 functions on 1 data structure
;; All of these work on your map:
(get person :name)
(assoc person :age 31)
(update person :age inc)
(select-keys person [:name :email])
(keys person)
(vals person)
(merge person {:title "Dr."})
;; Data doesn't change—you create new data
(def v1 [1 2 3])
(def v2 (conj v1 4))
v1 ;; Still [1 2 3]
v2 ;; [1 2 3 4]
;; Structural sharing makes this efficient
;; v1 and v2 share structure in memory
;; Update nested structures with assoc-in, update-in
(def user {:name "Alice"
:address {:city "Portland"
:zip "97201"}})
(def updated (assoc-in user [:address :city] "Seattle"))
;; user is unchanged, updated has new city
;; No defensive copying needed
(defn process [data]
;; data cannot be mutated, safe to pass around
(transform data))
;; When you need state, make it explicit
(def counter (atom 0))
;; Read state
@counter ;; 0
;; Update state (pure function applied atomically)
(swap! counter inc) ;; 1
(swap! counter + 10) ;; 11
;; State is in ONE place, not scattered through objects
;; Updates are explicit, not hidden in setters
;; For complex state, use a single atom with a map
(def app-state
(atom {:users {}
:sessions {}
:config {:debug false}}))
;; Update specific parts
(swap! app-state assoc-in [:config :debug] true)
(swap! app-state update-in [:users] assoc "alice" {:name "Alice"})
;; EASY but COMPLEX: Object with intertwined concerns
;; - State + identity + behavior all mixed
;; - Hard to test, hard to reason about
(defprotocol OrderProcessor
(add-item [this item])
(remove-item [this item-id])
(calculate-total [this])
(submit [this]))
;; SIMPLE: Separate concerns
;; Data (just values)
(def order {:items [] :status :draft})
;; Pure functions (no state)
(defn add-item [order item]
(update order :items conj item))
(defn calculate-total [order]
(reduce + (map :price (:items order))))
;; Side effects isolated
(defn submit-order! [order]
(db/save! order)
(email/send-confirmation! order))
;; Each piece is:
;; - Testable in isolation
;; - Understandable alone
;; - Recombinable
(require '[clojure.spec.alpha :as s])
;; Describe your data
(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::email (s/and string? #(re-matches #".+@.+" %)))
(s/def ::person
(s/keys :req-un [::name ::age ::email]))
;; Validate
(s/valid? ::person {:name "Alice" :age 30 :email "[email protected]"})
;; true
;; Explain failures
(s/explain ::person {:name "Alice" :age -5 :email "bad"})
;; :age - failed: pos-int?
;; :email - failed: regex match
;; Generate test data
(require '[clojure.spec.gen.alpha :as gen])
(gen/sample (s/gen ::person))
;; Problem: each step creates intermediate collections
(->> data
(map transform) ;; new collection
(filter valid?) ;; new collection
(take 10)) ;; new collection
;; Solution: transducers compose without intermediate collections
(def xform
(comp
(map transform)
(filter valid?)
(take 10)))
;; Apply to any collection type
(into [] xform data) ;; vector
(into #{} xform data) ;; set
(transduce xform + 0 data) ;; reduce
;; Same transformation, different contexts
;; No intermediate collections created
;; Values are immutable—they represent a point in time
;; This enables powerful patterns:
;; 1. History (undo/redo)
(def history (atom []))
(def current (atom {:count 0}))
(defn update-with-history! [f & args]
(swap! history conj @current)
(swap! current #(apply f % args)))
(defn undo! []
(when (seq @history)
(reset! current (peek @history))
(swap! history pop)))
;; 2. Snapshotting
(defn snapshot []
@app-state) ;; Returns immutable value
(def before (snapshot))
;; ... make changes ...
(def after (snapshot))
;; Compare states directly
(= before after)
(clojure.data/diff before after)
Ask these questions:
Hickey approaches design by asking:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience