← All skills
Clojure Developer
Use when building data-oriented systems with Clojure, REPL-driven development, persistent data structures, and Ring/Compojure.
About this skill
Use when building data-oriented systems with Clojure, REPL-driven development, persistent data structures, and Ring/Compojure.
SKILL.md
clojure-developer.SKILL.mdPlace it in your Syntic skills folder. For Syntic Code, install in your local skills directory, review the contents and run it in a controlled environment first.
---
name: Clojure Developer
description: Use when building data-oriented systems with Clojure, REPL-driven development, persistent data structures, and Ring/Compojure.
category: Languages
version: 1.0.0
tools: []
---
# Clojure Development
Build robust, data-oriented systems using functional programming and immutable data structures via REPL-driven development.
## REPL-Driven Development
1. Connect to a running REPL. Evaluate code forms incrementally rather than restarting the application.
2. Define functions and test them immediately with sample data before writing formal tests.
3. Use `comment` blocks (rich comments) at the bottom of each namespace for exploratory code and examples.
4. Reload changed namespaces with `require :reload` or `tools.namespace/refresh`. Design state management for safe reloads.
5. Use `tap>` and `add-tap` to inspect intermediate values without modifying production code.
## Data-Oriented Design
- Model entities as plain maps with namespaced keywords: `{:user/id 1 :user/name "Alice" :user/email "alice@example.com"}`.
- Use `clojure.spec.alpha` or Malli for schemas. Validate at system boundaries (API input, database output).
- Prefer data transformations over object methods. Functions operate on maps.
- Persistent data structures (vectors, maps, sets) provide structural sharing for efficient immutable updates.
- Represent state transitions as data: `{:event/type :order/placed :order/id "123" :order/items [...]}`.
## Web Applications with Ring
- HTTP handlers as pure functions: `(fn [request] response)`. Request is a map, response is a map.
- Compose middleware as function wrappers. Apply in order: logging → error handling → auth → routing → body parsing.
- **Compojure** or **Reitit** for routing. Reitit defines routes as data structures for better introspection.
- Return proper HTTP status codes and structured error responses. Use `ring.util.response` helpers.
- `ring.middleware.json` for JSON parsing/generation. `ring.middleware.params` for query strings.
## Concurrency Primitives
- **Atoms** for independent, synchronous state updates. `swap!` applies a pure function atomically.
- **Refs** and **STM** when multiple pieces of state must update in a coordinated transaction.
- **Agents** for independent, asynchronous state updates where order matters but timing does not.
- **core.async channels** for complex coordination: producer-consumer, pub-sub, pipeline processing.
- **Future** for simple fire-and-forget async computation. `deref` with timeout to avoid blocking.
## Namespace Organization
- One namespace per file. File names match namespace paths: `my_app/user/handler.clj` → `my-app.user.handler`.
- Separate concerns by layer: `my-app.user.handler` (HTTP), `my-app.user.service` (business logic), `my-app.user.db` (persistence).
- **Component** or **Integrant** for system lifecycle management.
- Keep namespace dependencies acyclic.
## ClojureScript
- **shadow-cljs** for builds. Configure `:target :browser` or `:target :node-library`.
- **Reagent** or **Re-frame** for React-based UIs. Reagent atoms drive reactive re-rendering.
- Interop: `js/` prefix for globals, `clj->js` / `js->clj` for data conversion.
- Google Closure Library utilities ship with ClojureScript at no extra bundle cost.
## Testing
- `clojure.test` with `deftest` and `is` assertions. Group with `testing` blocks.
- `test.check` for generative (property-based) testing. Define generators with `gen/fmap` and `gen/bind`.
- Test stateful systems by starting a test system with Component, running assertions, and stopping in a fixture.
Install
Syntic App
- 1Create a dedicated folder for this skill in your local skills library.
- 2Place SKILL.md into that folder.
- 3Restart Syntic and invoke this skill on matching tasks.
Syntic Code (CLI)
- 1Save SKILL.md in your local Syntic Code skills directory.
- 2Keep related files in the same skill folder.
- 3Run in a safe environment and validate outputs.