Unleashing the Power of clojure.spec: Insights from Clojure/conj 2016

Table of Contents

Background

clojure.spec received significant attention at Clojure/conj 2016 including:

  • Halloway's example for ETL,
  • Rohner's Spectrum,
  • Composing music with clojure.spec,
  • Normand's drawing examples, and
  • underpinings in Hickey's keynote.

Setup

Background on the rationale of clojure.spec is noted at https://clojure.org/about/spec . As noted it provices composability of entities with definitions similar to

Examples

Basic Specs

(require '[clojure.spec.alpha :as s])

;; Define a spec for a non-empty string
(s/def ::name (s/and string? #(> (count %) 0)))

;; Define a spec for an email
(s/def ::email (s/and string? #(re-matches #".+@.+\..+" %)))

;; Define a spec for age (positive integer)
(s/def ::age (s/and int? pos?))

;; Composite spec for a person
(s/def ::person (s/keys :req [::name ::email]
                        :opt [::age]))

;; Validation
(s/valid? ::person {::name "Alice" ::email "alice@example.com"})
;; => true

(s/explain ::person {::name "" ::email "invalid"})
;; => fails with explanation

Generative Testing

(require '[clojure.spec.gen.alpha :as gen])

;; Generate sample data
(gen/sample (s/gen ::name) 5)
;; => ("a" "xy" "abc" "test" "hello")

;; Generate valid persons
(gen/generate (s/gen ::person))
;; => {::name "xyz" ::email "a@b.com" ::age 42}

Function Specs

(defn greet [person]
  (str "Hello, " (::name person) "!"))

(s/fdef greet
  :args (s/cat :person ::person)
  :ret string?)

;; Instrument for development
(require '[clojure.spec.test.alpha :as stest])
(stest/instrument `greet)

Resources

Author: Jason Walsh

j@wal.sh

Last Updated: 2025-12-21 22:59:40

build: 2025-12-29 20:00 | sha: 34015db