Exemples de Langage Clojure

Exemples essentiels de programmation Clojure pour la programmation fonctionnelle sur la JVM

Key Facts

Category
Programming Languages
Items
3
Format Families
sample

Sample Overview

Exemples essentiels de programmation Clojure pour la programmation fonctionnelle sur la JVM This sample set belongs to Programming Languages and can be used to test related workflows inside Elysia Tools.

💻 Clojure Hello World clojure

🟢 simple ⭐⭐

Programme Hello World de base en Clojure et concepts fondamentaux de programmation fonctionnelle style Lisp

⏱️ 20 min 🏷️ clojure, functional, lisp, jvm, syntax
Prerequisites: Basic programming concepts, Understanding of functional programming
;; Clojure Hello World Examples

;; Load clojure.string for string helpers in script mode
(require '[clojure.string :as str])

;; 1. Basic Hello World
(println "Hello, World!")

;; 2. Hello World with function definition
(defn hello-world []
  (println "Hello, World!"))

(hello-world)

;; 3. Hello World with parameters
(defn greet [name]
  (println (str "Hello, " name "!")))

(greet "Clojure")
(greet "World")

;; 4. Hello World with multiple arities
(defn multi-greet
  ([] (println "Hello, World!"))
  ([name] (println (str "Hello, " name "!")))
  ([greeting name] (println (str greeting ", " name "!"))))

(multi-greet)
(multi-greet "Clojure")
(multi-greet "Good morning" "Clojure")

;; 5. Hello World with anonymous function
(let [greet-fn (fn [name] (println (str "Hello, " name "!")))]
  (greet-fn "Anonymous"))

;; 6. Hello World with higher-order function
(defn greet-twice [greet-fn name]
  (greet-fn name)
  (greet-fn name))

(greet-twice greet "Twice")

;; Basic data types and operations

;; Numbers
(def num1 42)
(def num2 3.14)
(def num3 2/3)  ; Rational number

(println "Integer:" num1)
(println "Float:" num2)
(println "Rational:" num3)
(println "Addition:" (+ num1 num2))
(println "Multiplication:" (* num1 2))

;; Strings
(def text "Clojure Programming")
(println "String:" text)
(println "Length:" (count text))
(println "Uppercase:" (str/upper-case text))
(println "Substring:" (subs text 0 6))

;; Keywords (efficient identifiers)
(def status :active)
(def user {:name "Alice" :age 30 :status status})
(println "User:" user)
(println "User name:" (:name user))
(println "User age:" (:age user))

;; Vectors (ordered collections)
(def numbers [1 2 3 4 5])
(println "Vector:" numbers)
(println "First element:" (first numbers))
(println "Last element:" (last numbers))
(println "Rest:" (rest numbers))
(println "Conj:" (conj numbers 6))

;; Maps (key-value collections)
(def person {
  :name "Bob"
  :age 25
  :city "New York"
  :hobbies ["reading" "coding" "music"]
})

(println "Person:" person)
(println "Person name:" (:name person))
(println "Person hobbies:" (:hobbies person))

;; Sets (unique collections)
(def unique-numbers #{1 2 3 4 5})
(println "Set:" unique-numbers)
(println "Contains 3?" (contains? unique-numbers 3))
(println "Add element:" (conj unique-numbers 6))

;; Lists (linked lists)
(def list-data '(1 2 3 4 5))
(println "List:" list-data)
(println "First:" (first list-data))
(println "Rest:" (rest list-data))

;; Basic functions

;; Function with multiple return values (using vector)
(defn divide-and-remainder [dividend divisor]
  (let [quotient (quot dividend divisor)
        remainder (rem dividend divisor)]
    [quotient remainder]))

(let [[q r] (divide-and-remainder 17 5)]
  (println "17 ÷ 5 =" q "remainder" r))

;; Conditional logic
(defn describe-number [n]
  (cond
    (< n 0) "negative"
    (= n 0) "zero"
    (< n 10) "small positive"
    :else "large positive"))

(println "-5 is" (describe-number -5))
(println "0 is" (describe-number 0))
(println "5 is" (describe-number 5))
(println "15 is" (describe-number 15))

;; Pattern matching with case
(defn describe-value [x]
  (case x
    1 "one"
    2 "two"
    3 "three"
    "hello" "greeting"
    :keyword "a keyword"
    "unknown value"))

(println "Value of 1:" (describe-value 1))
(println "Value of 'hello':" (describe-value "hello"))

;; Recursion
(defn factorial [n]
  (if (<= n 1)
    1
    (* n (factorial (dec n)))))

(println "5! =" (factorial 5))

;; Tail recursion optimization
(defn factorial-tail [n acc]
  (if (<= n 1)
    acc
    (recur (dec n) (* n acc))))

(defn factorial [n]
  (factorial-tail n 1))

(println "10! =" (factorial 10))

;; Loop/recur for iteration
(defn sum-to [n]
  (loop [i 1 total 0]
    (if (> i n)
      total
      (recur (inc i) (+ total i)))))

(println "Sum of 1 to 100:" (sum-to 100))

;; Higher-order functions

;; Map - transform each element
(def doubled (map #(* % 2) [1 2 3 4 5]))
(println "Doubled:" doubled)

;; Filter - select elements
(def evens (filter even? [1 2 3 4 5 6]))
(println "Even numbers:" evens)

;; Reduce - aggregate elements
(def sum (reduce + [1 2 3 4 5]))
(println "Sum:" sum)

;; Function composition
(defn add-and-double [x]
  (-> x
      (+ 5)
      (* 2)))

(println "Add 5 and double 10:" (add-and-double 10))

;; Destructuring
(defn process-person [{:keys [name age city] :as person}]
  (println (str name " is " age " years old and lives in " city))
  (println "Full person data:" person))

(process-person {:name "Charlie" :age 35 :city "Boston"})

;; Vector destructuring
(defn process-coordinates [[x y z]]
  (println (str "X: " x ", Y: " y ", Z: " z)))

(process-coordinates [10 20 30])

;; Lazy sequences
(def naturals (iterate inc 1))
(def first-10 (take 10 naturals))
(println "First 10 natural numbers:" first-10)

(def even-numbers (filter even? naturals))
(def first-5-evens (take 5 even-numbers))
(println "First 5 even numbers:" first-5-evens)

;; Interoperability with Java
(import 'java.util.Date)
(import 'java.text.SimpleDateFormat)

(defn format-date [date]
  (let [formatter (SimpleDateFormat. "yyyy-MM-dd HH:mm:ss")]
    (.format formatter date)))

(def now (Date.))
(println "Current time:" (format-date now))

;; Using Java collections
(def java-list (java.util.ArrayList.))
(.add java-list "Java element")
(.add java-list "Another element")
(println "Java list:" (vec java-list))

;; Namespaces and requires (in real usage)
;; (ns my-app.core
;;   (:require [clojure.string :as str]
;;             [clojure.set :as set]))

;; Exception handling
(defn safe-divide [a b]
  (try
    (/ a b)
    (catch ArithmeticException e
      (println "Division by zero error!")
      nil)
    (finally
      (println "Division operation completed"))))

(println "10 ÷ 2 =" (safe-divide 10 2))
(println "10 ÷ 0 =" (safe-divide 10 0))

;; Atom for state management
(def counter (atom 0))

(defn increment-counter []
  (swap! counter inc))

(defn get-counter []
  @counter)

(println "Initial counter:" @counter)
(increment-counter)
(increment-counter)
(println "Final counter:" @counter)

;; Basic meta-programming
(defmacro debug [x]
  (let [result# ~x]
     (println (str '~x " = " result#))
     result#))

(def a 10)
(def b 20)
(debug (+ a b))

💻 Patrons de Programmation Fonctionnelle Clojure clojure

🟡 intermediate ⭐⭐⭐⭐

Techniques avancées de programmation fonctionnelle, structures de données immutables et patrons communs Clojure

⏱️ 30 min 🏷️ clojure, functional, patterns, immutable, protocols
Prerequisites: Clojure basics, Functional programming concepts, Data structures
;; Clojure Functional Programming Patterns

;; 1. Pure Functions and Immutability

;; Pure function - no side effects
(defn calculate-discount [price discount-rate]
  (* price (- 1 discount-rate)))

(println "Discounted price:" (calculate-discount 100 0.2))

;; Always return new data structures instead of modifying
(defn add-item-to-cart [cart item]
  (conj cart item))

(def original-cart [:book :pen])
(def new-cart (add-item-to-cart original-cart :notebook))
(println "Original cart:" original-cart)  ; Unchanged
(println "New cart:" new-cart)            ; New cart with added item

;; 2. Function Composition and Transducers

;; Function composition
(defn transform-data [data]
  (->> data
       (map #(* % 2))           ; Double each number
       (filter even?)            ; Keep only even numbers
       (take 5)                  ; Take first 5
       (reduce +)))              ; Sum them up

(def numbers (range 1 20))
(println "Transform result:" (transform-data numbers))

;; Transducers - composable algorithmic transformations
(def xf-map-double (map #(* % 2)))
(def xf-filter-evens (filter even?))
(def xf-take-five (take 5))

(def process-numbers
  (comp xf-map-double xf-filter-evens xf-take-five))

(println "Transducer result:" (into [] process-numbers numbers))

;; 3. Lazy Sequences and Infinite Data

;; Infinite sequence of Fibonacci numbers
(def fib-seq
  (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))

(def first-10-fib (take 10 fib-seq))
(println "First 10 Fibonacci numbers:" first-10-fib)

;; Lazy prime numbers
(defn prime? [n]
  (and (> n 1)
       (not-any? #(zero? (rem n %)) (range 2 (Math/sqrt n)))))

(def primes (filter prime? (iterate inc 2)))
(def first-10-primes (take 10 primes))
(println "First 10 prime numbers:" first-10-primes)

;; 4. Higher-Order Functions and Closures

;; Function factory - creates functions with captured values
(defn make-adder [increment]
  (fn [x] (+ x increment)))

(def add-5 (make-adder 5))
(def add-10 (make-adder 10))
(println "Add 5 to 10:" (add-5 10))
(println "Add 10 to 10:" (add-10 10))

;; Predicate factory
(defn make-predicate [operator value]
  (fn [x] (operator x value)))

(def greater-than-5 (make-predicate > 5))
(def less-than-10 (make-predicate < 10))
(println "Numbers >5:" (filter greater-than-5 [1 3 6 8 2 10]))
(println "Numbers <10:" (filter less-than-10 [1 3 6 8 2 10]))

;; 5. Data Transformation Pipelines

;; Pipeline for processing user data
(defn process-user-data [raw-users]
  (->> raw-users
       ;; Remove inactive users
       (filter #(:active %))
       ;; Calculate age group
       (map #(assoc % :age-group
                    (cond
                      (< (:age %) 18) "minor"
                      (< (:age %) 65) "adult"
                      :else "senior")))
       ;; Sort by age
       (sort-by :age)
       ;; Extract only relevant fields
       (map #(select-keys % [:name :age :age-group]))))

(def raw-users [
  {:name "Alice" :age 25 :active true :email "[email protected]"}
  {:name "Bob" :age 17 :active true :email "[email protected]"}
  {:name "Charlie" :age 70 :active false :email "[email protected]"}
  {:name "Diana" :age 30 :active true :email "[email protected]"}])

(println "Processed users:" (process-user-data raw-users))

;; 6. Recursive Patterns and Tree Processing

;; Generic tree processing
(defn process-tree [node f-leaf f-node]
  (if (:children node)
    (f-node (:value node)
            (map #(process-tree % f-leaf f-node) (:children node)))
    (f-leaf (:value node))))

(def sample-tree
  {:value "root"
   :children [
    {:value "left" :children [
      {:value "left-left"}
      {:value "left-right"}
    ]}
    {:value "right" :children [
      {:value "right-left"}
    ]}
  ]})

(defn sum-leaves [x]
  (if (number? x) x 0))

(defn sum-node [value child-sums]
  (+ (sum-leaves value) (reduce + child-sums)))

(def numeric-tree
  {:value 1
   :children [
    {:value 2 :children [{:value 3} {:value 4}]}
    {:value 5 :children [{:value 6}]}
  ]})

(println "Tree sum:" (process-tree numeric-tree sum-leaves sum-node))

;; 7. Memoization and Caching

;; Memoized expensive function
(defn slow-fibonacci [n]
  (if (< n 2)
    n
    (+ (slow-fibonacci (dec n)) (slow-fibonacci (- n 2)))))

(def memo-fibonacci (memoize slow-fibonacci))

(println "Memoized fib 40:" (memo-fibonacci 40))  ; Much faster

;; Cache with TTL (time-to-live)
(defn create-ttl-cache [ttl-ms]
  (let [cache (atom {})]
    (fn [key f]
      (let [now (System/currentTimeMillis)
            cached-value (get @cache key)]
        (if (and cached-value (< (- now (:timestamp cached-value)) ttl-ms))
          (:value cached-value)
          (let [new-value (f)]
            (swap! cache assoc key {:value new-value :timestamp now})
            new-value))))))

(def expensive-cache (create-ttl-cache 5000))  ; 5 second TTL

(defn expensive-calculation [x]
  (println "Performing expensive calculation for" x)
  (* x x x))

(println "Cached result:" (expensive-cache 10 expensive-calculation))
(println "Cached result again:" (expensive-cache 10 expensive-calculation))

;; 8. State Management Patterns

;; Event sourcing pattern
(defn add-event [state event]
  (case (:type event)
    :add-item (update state :items conj (:item event))
    :remove-item (update state :items disj (:item event))
    :update-quantity (assoc-in state [:quantities (:item event)] (:quantity event))
    state))

(def initial-state {:items #{} :quantities {}})

(def events [
  {:type :add-item :item :book}
  {:type :add-item :item :pen}
  {:type :update-quantity :item :book :quantity 2}
  {:type :remove-item :item :pen}
])

(def final-state (reduce add-event initial-state events))
(println "Final state:" final-state)

;; 9. Protocol and Multimethod Patterns

;; Multimethods for polymorphic behavior
(defmulti area :shape)

(defmethod area :circle [{:keys [radius]}]
  (* Math/PI radius radius))

(defmethod area :rectangle [{:keys [width height]}]
  (* width height))

(defmethod area :triangle [{:keys [base height]}]
  (* 0.5 base height))

(def shapes [
  {:shape :circle :radius 5}
  {:shape :rectangle :width 4 :height 6}
  {:shape :triangle :base 3 :height 8}
])

(println "Areas:" (map area shapes))

;; Protocols for interface-like behavior
(defprotocol Drawable
  (draw [this]))

(defrecord Circle [radius]
  Drawable
  (draw [this]
    (println (str "Drawing circle with radius " radius))))

(defrecord Rectangle [width height]
  Drawable
  (draw [this]
    (println (str "Drawing rectangle " width "x" height))))

(def shapes-objects [(->Circle 10) (->Rectangle 5 8)])
(dorun (map draw shapes-objects))

;; 10. Error Handling and Validation

;; Result pattern with explicit success/failure
(defn safe-divide [a b]
  (if (zero? b)
    {:success false :error "Division by zero"}
    {:success true :result (/ a b)}))

(defn chain-operations [initial operations]
  (reduce (fn [acc op]
            (if (:success acc)
              (op (:result acc))
              acc))
          initial
          operations))

(def calculation-pipeline [
  #(safe-divide % 2)    ; Divide by 2
  #(safe-divide % 0)    ; This will fail
  #(safe-divide % 3)])  ; This won't be reached

(println "Calculation result:" (chain-operations 100 calculation-pipeline))

;; Validation with accumulation
(defn validate-user [user]
  (let [errors (cond-> []
                 (empty? (:name user)) (conj "Name is required")
                 (not (:email user)) (conj "Email is required")
                 (and (:age user) (< (:age user) 0)) (conj "Age must be non-negative"))]
    (if (empty? errors)
      {:success true :user user}
      {:success false :errors errors})))

(def test-users [
  {:name "Alice" :email "[email protected]" :age 25}
  {:name "" :email "[email protected]" :age -5}
  {}])

(println "Validation results:" (map validate-user test-users))

💻 Développement Web et Macros Clojure clojure

🔴 complex ⭐⭐⭐⭐⭐

Développement web avec Ring/Compojure et programmation de macros avancée pour métaprogrammation

⏱️ 45 min 🏷️ clojure, web, macros, ring, compojure, api
Prerequisites: Advanced Clojure, Web concepts, Database knowledge, Macro understanding
;; Clojure Web Development and Advanced Macros

;; 1. Ring and Compojure Web Framework Basics

;; Basic Ring handler
(defn hello-handler [request]
  {:status 200
   :headers {"Content-Type" "text/html"}
   :body "<h1>Hello from Clojure!</h1>"})

;; Route-based handler with Compojure
(require '[compojure.core :refer [defroutes GET POST]])
(require '[ring.adapter.jetty :as jetty])

(defroutes app-routes
  (GET "/" [] "Welcome to the homepage!")
  (GET "/hello/:name" [name] (str "Hello, " name "!"))
  (GET "/api/users" []
    {:status 200
     :headers {"Content-Type" "application/json"}
     :body "[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]"})
  (POST "/api/users" [name email]
    {:status 201
     :headers {"Content-Type" "application/json"}
     :body (str "{"id":3,"name":"" name "","email":"" email ""}")})
  (GET "/files/:filename" [filename]
    (java.io.File. "public/" filename)))

;; Middleware for logging
(defn wrap-logging [handler]
  (fn [request]
    (println (str "Processing " (:request-method request) " " (:uri request)))
    (let [response (handler request)]
      (println (str "Response status: " (:status response)))
      response)))

;; Middleware for JSON responses
(defn wrap-json [handler]
  (fn [request]
    (let [response (handler request)]
      (if (map? (:body response))
        (assoc-in response [:headers "Content-Type"] "application/json")
        response))))

;; Middleware stack
(def app
  (-> app-routes
      wrap-logging
      wrap-json))

;; 2. Advanced Macro Programming

;; Macro for route definition with automatic documentation
(defmacro defpage [route description & body]
  (do
     (defn ~(symbol (str "page-" (hash route))) [request#]
       ~@body)
     (alter-var-root #'*routes* conj {:path ~route :description ~description})
     ~(symbol (str "page-" (hash route)))))

(def *routes* (atom []))

(defpage "/about" "About page"
  {:status 200
   :headers {"Content-Type" "text/html"}
   :body "<h1>About Us</h1><p>We are a Clojure web application!</p>"})

;; Debugging macro with expression information
(defmacro dbg [x]
  (let [result# ~x]
     (println (str "Debug: " '~x " = " result#))
     result#))

;; Time execution macro
(defmacro time-execution [& body]
  (let [start# (System/nanoTime)
         result# (do ~@body)
         end# (System/nanoTime)
         duration# (/ (- end# start#) 1000000.0)]
     (println (str "Execution time: " duration# " ms"))
     result#))

;; Usage example:
;; (time-execution
;;   (Thread/sleep 100)
;;   (println "Done"))

;; Conditional compilation macro
(defmacro when-dev [& body]
  (when (= "development" (or (System/getenv "ENV") "development"))
     ~@body))

(when-dev
  (println "Development mode enabled"))

;; 3. Database Operations and Transactions

(require '[clojure.java.jdbc :as jdbc])

(def db-spec {:subprotocol "h2"
              :subname "mem:example"
              :user "sa"
              :password ""})

;; Table creation
(defn create-users-table! []
  (jdbc/db-do-commands db-spec
    [(jdbc/create-table-ddl :users
       [[:id :int "PRIMARY KEY"]
        [:name "VARCHAR(50)"]
        [:email "VARCHAR(100)"]
        [:created_at :timestamp]])]))

;; CRUD operations
(defn create-user! [user-data]
  (jdbc/insert! db-spec :users
    (assoc user-data :created_at (java.sql.Timestamp. (System/currentTimeMillis)))))

(defn get-user [id]
  (first (jdbc/query db-spec ["SELECT * FROM users WHERE id = ?" id])))

(defn update-user! [id user-data]
  (jdbc/update! db-spec :users user-data ["id = ?" id]))

(defn delete-user! [id]
  (jdbc/delete! db-spec :users ["id = ?" id]))

(defn list-users []
  (jdbc/query db-spec ["SELECT * FROM users ORDER BY created_at DESC"]))

;; Transaction example
(defn transfer-users! [from-id to-id]
  (jdbc/with-db-transaction [t-conn db-spec]
    (let [from-user (first (jdbc/query t-conn ["SELECT * FROM users WHERE id = ?" from-id]))
          to-user (first (jdbc/query t-conn ["SELECT * FROM users WHERE id = ?" to-id]))]
      (when (and from-user to-user)
        ;; Update both users in a single transaction
        (jdbc/update! t-conn :users
          {:name (str (:name from-user) "_transferred")}
          ["id = ?" from-id])
        (jdbc/update! t-conn :users
          {:name (str (:name to-user) "_received")}
          ["id = ?" to-id])
        true))))

;; 4. Authentication and Authorization

;; Password hashing
(require '[buddy.hashers :as hashers])

(defn hash-password [password]
  (hashers/derive password {:algorithm :bcrypt}))

(defn verify-password [password hashed-password]
  (hashers/verify password hashed-password))

;; JWT token generation (requires buddy-sign)
(require '[buddy.sign.jwt :as jwt])

(def secret-key "your-secret-key-here")

(defn generate-token [user-id]
  (jwt/sign {:user-id user-id :exp (+ (System/currentTimeMillis) 3600000)} secret-key))

(defn verify-token [token]
  (try
    (jwt/unsign token secret-key)
    (catch Exception e
      {:error "Invalid token"})))

;; Authentication middleware
(defn wrap-authentication [handler]
  (fn [request]
    (let [token (get-in request [:headers "authorization"])
          auth-result (when token (verify-token token))]
      (if (:error auth-result)
        {:status 401 :body {:error "Unauthorized"}}
        (handler (assoc request :user (:data auth-result)))))))

;; Authorization macro
(defmacro require-role [role & body]
  (let [user# (:user *request*)]
     (if (= (:role user#) ~role)
       (do ~@body)
       {:status 403 :body {:error "Forbidden"}})))

;; 5. RESTful API with Data Validation

;; Validation library usage
(require '[clojure.spec.alpha :as s])

(s/def ::name string?)
(s/def ::email #(re-matches #".+@.+..+" %))
(s/def ::age int?)
(s/def ::user (s/keys :req-un [::name ::email]
                    :opt-un [::age]))

(defn validate-request [data spec]
  (if (s/valid? spec data)
    {:success true :data data}
    {:success false :errors (s/explain-data spec data)}))

;; API endpoint with validation
(defn create-user-api [request]
  (let [user-data (:body request)
        validation (validate-request user-data ::user)]
    (if (:success validation)
      (try
        (let [created-user (create-user! (:data validation))]
          {:status 201 :body created-user})
        (catch Exception e
          {:status 500 :body {:error "Database error"}}))
      {:status 400 :body {:errors (:errors validation)}})))

;; 6. Real-time WebSocket Communication

(require '[ring.adapter.jetty :as jetty])
(require '[clojure.data.json :as json])

(def websocket-connections (atom #{}))

(defn websocket-handler [request]
  {:status 101
   :headers {"Upgrade" "websocket"
            "Connection" "Upgrade"}})

(defn broadcast-message! [message]
  (doseq [connection @websocket-connections]
    (try
      (.send connection (json/write-str message))
      (catch Exception e
        (swap! websocket-connections disj connection)))))

(defn handle-websocket-message [connection message]
  (let [parsed (json/read-str message)]
    (case (:type parsed)
      :chat (broadcast-message!
             {:type :chat
              :user (:user parsed)
              :message (:message parsed)
              :timestamp (System/currentTimeMillis)})
      :join (swap! websocket-connections conj connection))))

;; 7. Background Jobs and Task Queue

;; Simple task queue using atoms
(def task-queue (atom clojure.lang.PersistentQueue/EMPTY))
(def workers (atom {}))

(defn enqueue-task! [task]
  (swap! task-queue conj task))

(defn dequeue-task! []
  (first (swap-vals! task-queue pop)))

(defn start-worker! [worker-id]
  (future
    (loop []
      (when-let [task (dequeue-task!)]
        (try
          (println (str "Worker " worker-id " processing task: " (:type task)))
          ((:handler task) task)
          (catch Exception e
            (println (str "Worker " worker-id " error: " (.getMessage e)))))
        (recur)))))

(defn stop-worker! [worker-id]
  (when-let [worker-future (get @workers worker-id)]
    (future-cancel worker-future)
    (swap! workers dissoc worker-id)))

;; Example tasks
(defn send-email-task [task]
  (Thread/sleep 2000)  ; Simulate sending email
  (println (str "Email sent to " (:to task))))

(defn process-image-task [task]
  (Thread/sleep 5000)  ; Simulate image processing
  (println (str "Image processed: " (:image-path task))))

;; Enqueue tasks
(enqueue-task! {:type :send-email
                :to "[email protected]"
                :handler send-email-task})

(enqueue-task! {:type :process-image
                :image-path "/path/to/image.jpg"
                :handler process-image-task})

;; Start worker threads
(swap! workers assoc :worker1 (start-worker! 1))
(swap! workers assoc :worker2 (start-worker! 2))

;; 8. Configuration Management

;; Configuration loading
(defn load-config [env]
  (case env
    :development {:port 3000 :db-url "jdbc:h2:mem:dev" :debug true}
    :test {:port 3001 :db-url "jdbc:h2:mem:test" :debug false}
    :production {:port 80 :db-url "jdbc:postgresql://prod/db" :debug false}
    {:port 3000 :db-url "jdbc:h2:mem:default" :debug false}))

(def config (load-config (keyword (or (System/getenv "ENV") "development"))))

;; Environment-specific middleware
(defn wrap-dev-only [handler]
  (if (:debug config)
    handler
    (fn [request] {:status 404 :body "Not found"})))

;; 9. Error Handling and Logging

;; Structured logging
(defn log-event [level message data]
  (let [log-entry {:timestamp (System/currentTimeMillis)
                   :level level
                   :message message
                   :data data}]
    (println (clojure.data.json/write-str log-entry))
    log-entry))

;; Global error handler
(defn wrap-error-handling [handler]
  (fn [request]
    (try
      (handler request)
      (catch Exception e
        (log-event :error "Unhandled exception"
                   {:exception (.getMessage e)
                    :stack-trace (map str (.getStackTrace e))})
        {:status 500 :body {:error "Internal server error"}}))))

;; 10. Testing and Development Tools

;; Test data generation
(defn generate-test-user []
  {:name (str "Test User " (rand-int 1000))
   :email (str "test" (rand-int 1000) "@example.com")
   :age (+ 18 (rand-int 50))})

;; Route testing helper
(defn test-route [app-routes request-method uri]
  ((app-routes {:request-method request-method :uri uri}) {}))

;; Start the server (comment out in production)
;; (jetty/run-jetty app {:port (:port config) :join? false})