<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: clojure</title>
    <description>The latest articles tagged 'clojure' on DEV Community.</description>
    <link>https://dev.to/t/clojure</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tag/clojure"/>
    <language>en</language>
    <item>
      <title>Leiningen — Complete Tutorial &amp; Best Practices</title>
      <dc:creator>ivan.gavlik</dc:creator>
      <pubDate>Sun, 12 Apr 2026 11:23:33 +0000</pubDate>
      <link>https://dev.to/ivangavlik/leiningen-complete-tutorial-best-practices-3f8l</link>
      <guid>https://dev.to/ivangavlik/leiningen-complete-tutorial-best-practices-3f8l</guid>
      <description>&lt;p&gt;Leiningen is the build tool and project manager for Clojure. Think of it&lt;br&gt;
  like npm (Node), Maven (Java), or pip (Python) — but designed around&lt;br&gt;
  Clojure's philosophy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Leiningen Does&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates and scaffolds projects&lt;/li&gt;
&lt;li&gt;Manages dependencies (from Clojars + Maven Central)&lt;/li&gt;
&lt;li&gt;Runs REPLs, tests, and builds&lt;/li&gt;
&lt;li&gt;Compiles and packages your app (JAR/uberjar)&lt;/li&gt;
&lt;li&gt;Runs custom tasks via plugins&lt;/li&gt;
&lt;li&gt;Manages profiles (dev/test/prod configs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;br&gt;
  my-app/&lt;br&gt;
  ├── project.clj          ← The heart: dependencies, config, build&lt;br&gt;
  ├── src/&lt;br&gt;
  │   └── my_app/&lt;br&gt;
  │       └── core.clj     ← Main namespace (note: _ not - in folders)&lt;br&gt;
  ├── test/&lt;br&gt;
  │   └── my_app/&lt;br&gt;
  │       └── core_test.clj&lt;br&gt;
  ├── resources/           ← Static files, config, assets&lt;br&gt;
  ├── target/              ← Compiled output (git-ignore this)&lt;br&gt;
  └── README.md&lt;/p&gt;

&lt;p&gt;Note: Clojure namespaces use - (hyphens), but folder/file names use _ (underscores). my-app.core → src/my_app/core.clj&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;project.clj&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.0-SNAPSHOT"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"What this project does"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://github.com/you/my-app"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:license&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;;; Dependencies: [group/artifact "version"]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.12.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.12.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hiccup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.0.0-RC3"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;;; Entry point for `lein run`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;;; Source paths&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:source-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:test-paths&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:resource-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"resources"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;;; AOT compile specific namespaces (needed for uberjar)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my-app.core&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;;; Profiles: override config per environment&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;]]}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:prod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:uberjar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:omit-source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real world Example
&lt;/h2&gt;

&lt;p&gt;Shows how do declare dependencies, plugins on project and profil level plus advanced usages of aliases&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp-be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.0-SNAPSHOT"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Backend project for Event Booking Platform."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://github.com/IvanGavlik/ebp"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:license&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.12.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-jetty-adapter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.12.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.5.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;compojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.7.1"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; project level plugins&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.12.6"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.5.0"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; lein-ring plugin config - points to handler&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp.handler/app&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:auto-reload?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:reload-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp.handler/app-init&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:destroy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp.handler/app-destroy&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:open-browser?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:war&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ebp-be"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; entry point&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ebp.core&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="no"&gt;:source-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:test-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:resource-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"resources"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="no"&gt;:uberjar-name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ebp-be.jar"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.6.2"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.9.2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-kibit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.11"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jonase/eastwood&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.4.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;com.jakemccrary/lein-test-refresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.26.0"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="c1"&gt;;; lein-ancient plugin config&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="no"&gt;:ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:check-clojure?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="no"&gt;:allow-snapshots?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
                             &lt;/span&gt;&lt;span class="no"&gt;:allow-qualified?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="no"&gt;:cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:indentation?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="no"&gt;:remove-trailing-whitespace?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="no"&gt;:insert-missing-whitespace?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="no"&gt;:remove-surrounding-whitespace?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="no"&gt;:eastwood&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:linters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="no"&gt;:test-refresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:changes-only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="c1"&gt;;; production build&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="no"&gt;:uberjar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:omit-source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"do"&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"shell"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"cmd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/c"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"cmd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/k"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"lein"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ring"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"server-headless"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"shell"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"cmd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/c"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"cmd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/k"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"lein"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"test-refresh"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"repl"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s"&gt;"code-quality"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"do"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"cljfmt"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;"fix,"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"eastwood,"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"kibit,"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"test,"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="c1"&gt;;"ancient" ":all" ":profiles" does not work on windows&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s"&gt;"ci"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"do"&lt;/span&gt;&lt;span class="w"&gt;
                       &lt;/span&gt;&lt;span class="s"&gt;"clean,"&lt;/span&gt;&lt;span class="w"&gt;
                       &lt;/span&gt;&lt;span class="s"&gt;"cljfmt"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;"check,"&lt;/span&gt;&lt;span class="w"&gt;
                       &lt;/span&gt;&lt;span class="s"&gt;"eastwood,"&lt;/span&gt;&lt;span class="w"&gt;
                       &lt;/span&gt;&lt;span class="s"&gt;"test,"&lt;/span&gt;&lt;span class="w"&gt;
                       &lt;/span&gt;&lt;span class="s"&gt;"uberjar"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full source code &lt;a href="https://github.com/IvanGavlik/ebp" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Explanation of each of the sections&lt;/p&gt;

&lt;h2&gt;
  
  
  Profiles
&lt;/h2&gt;

&lt;p&gt;You can put inside a profile almost anything that goes in &lt;code&gt;project.clj&lt;/code&gt; at the top level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; extra deps for this profile&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; extra plugins&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:source-paths&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; extra source dirs&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:resource-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; extra resource dirs&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:env&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; env vars (needs lein-environ)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:jvm-opts&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; JVM flags&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:main&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; override entry point&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; override AOT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate a profile:&lt;br&gt;
&lt;code&gt;lein with-profile prod run&lt;/code&gt;&lt;br&gt;
&lt;code&gt;lein with-profile dev,test test   # multiple profiles&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Profiles merge, with later ones winning. :dev is active by default in most commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Patterns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separate DB per environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"jdbc:postgresql://localhost/app_dev"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"jdbc:postgresql://localhost/app_test"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dev-only tools that don't ship&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;clj-reload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;eftest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.6.0"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.9.2"&lt;/span&gt;&lt;span class="p"&gt;]]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different JVM memory per task&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:jvm-opts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"-Xmx512m"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:uberjar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:jvm-opts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"-Xmx2g"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-server"&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extra source dir for dev utilities&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:source-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dev/user.clj&lt;/code&gt; — good place for REPL helper functions and startup code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Plugins extend what lein can do. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where to Put Them&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Global — your personal machine only&lt;br&gt;
Good for personal tools you want in every project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; ~/.lein/profiles.clj  (not in the project repo)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:user&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-pprint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.3.2"&lt;/span&gt;&lt;span class="p"&gt;]]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Top-level — for everyone on the project&lt;br&gt;
Committed to git. Every developer gets these when they clone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.0-SNAPSHOT"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.12.6"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside a profile — conditional&lt;br&gt;
Only active when that profile is active.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-test-refresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.25.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.9.2"&lt;/span&gt;&lt;span class="p"&gt;]]}&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="no"&gt;:uberjar&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.5.0"&lt;/span&gt;&lt;span class="p"&gt;]]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Most Useful Plugins
&lt;/h3&gt;

&lt;p&gt;Web Development&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; Run Ring/Compojure apps with auto-reload&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.12.6"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; open browser automatically&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server-headless&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uberjar&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; build deployable war&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; ring config in project.clj&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:ring&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c1"&gt;;; Required: your main handler function&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core/app&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Port (default 3000, overridden by $PORT env var)&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Auto-reload namespaces on file change&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:auto-reload?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Which namespaces to watch for reload&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:reload-paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Run this function before server starts&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core/init&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Run this function when server stops&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:destroy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core/destroy&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; Open browser on start (default true with `lein ring server`)&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:open-browser?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="c1"&gt;;; For WAR packaging: servlet name&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;:war&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"my-app"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing Ring Handlers&lt;/p&gt;

&lt;p&gt;Use ring-mock — no server needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;]]}}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core-test&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clojure.test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:refer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring.mock.request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my-app.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:refer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;]]))&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deftest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test-home&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mock/request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deftest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test-not-found&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mock/request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/missing"&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deftest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test-post&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mock/request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mock/json-body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;})))]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; Auto-run tests on file save&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-test-refresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.25.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test-refresh&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; Test coverage report&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cloverage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.2.4"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cloverage&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;;; generates target/coverage/index.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code Quality&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; Format code (like Prettier)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.9.2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; show formatting issues&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cljfmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fix&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;; auto-fix them&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; Linter — catches common bugs&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jonase/eastwood&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.4.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eastwood&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; Suggest more idiomatic Clojure&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-kibit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.8"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kibit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependency Management&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; Check for outdated dependencies&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancient&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;; check deps&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;; check deps + plugins&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; auto-update versions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Finding Plugins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://clojars.org" rel="noopener noreferrer"&gt;https://clojars.org&lt;/a&gt; — search for lein-*&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/technomancy/leiningen/wiki/Plugins" rel="noopener noreferrer"&gt;https://github.com/technomancy/leiningen/wiki/Plugins&lt;/a&gt; — official plugin
list&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;Shortcuts that let you define custom lein commands in project.clj. Instead of typing long commands repeatedly, you define them once and run them with a short name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple Aliases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Single task shortcut&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"fmt"&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"cljfmt"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"fix"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"lint"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"eastwood"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"hints"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"kibit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ring"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of call&lt;br&gt;
&lt;code&gt;lein fmt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chaining Tasks with do&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run multiple tasks sequentially — use commas to separate task+args groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"ci"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"do"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s"&gt;"clean,"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s"&gt;"eastwood,"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s"&gt;"kibit,"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s"&gt;"test,"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s"&gt;"uberjar"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;lein ci     ; clean → lint → analyze → test → build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note: The commas are part of the syntax — they tell do where one task ends and the next begins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Profile + Task Combos&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:aliases&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s"&gt;"ring"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"prod-run"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"prod"&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"ci-test"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="s"&gt;"build"&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"with-profile"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"uberjar"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"uberjar"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;lein dev       ; start dev server with :dev profile&lt;/code&gt;&lt;br&gt;
&lt;code&gt;lein build     ; build production jar with :uberjar profil&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why AOT Compilation?
&lt;/h2&gt;

&lt;p&gt;AOT = Ahead-Of-Time compilation&lt;/p&gt;

&lt;p&gt;Normally Clojure compiles at runtime (when the JVM starts). AOT means&lt;br&gt;
compiling to .class files before runtime, at build time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem It Solves&lt;/strong&gt;&lt;br&gt;
When you run a JAR, the JVM needs a standard Java entry point:&lt;br&gt;
&lt;code&gt;public static void main(String[] args)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Clojure's &lt;code&gt;-main&lt;/code&gt; function is not that. It's a Clojure function that gets compiled on the fly when the JVM starts.&lt;/p&gt;

&lt;p&gt;Without AOT, the JVM has no idea where to start. It can't find a main&lt;br&gt;
method.&lt;/p&gt;

&lt;p&gt;AOT compiles your &lt;code&gt;-main&lt;/code&gt; namespace into real &lt;code&gt;.class&lt;/code&gt; files with a proper Java main method the JVM can call directly.&lt;/p&gt;

&lt;p&gt;What Happens With vs Without AOT ?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without AOT (lein run):&lt;/strong&gt;&lt;br&gt;
    JVM starts&lt;br&gt;
      → loads Clojure runtime&lt;br&gt;
        → Clojure compiles your namespaces on the fly&lt;br&gt;
          → calls -main&lt;br&gt;
    (works fine because lein handles the startup)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With AOT (java -jar my-app.jar):&lt;/strong&gt;&lt;br&gt;
    JVM starts&lt;br&gt;
      → looks for main class in MANIFEST.MF&lt;br&gt;
        → finds compiled .class file  ← AOT produced this&lt;br&gt;
          → calls -main&lt;br&gt;
    (works because the class file exists)&lt;/p&gt;

&lt;p&gt;Concrete Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my-app.core&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:gen-class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; ← this is also required! tells AOT to generate a&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nb"&gt;class&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Hello!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;:gen-class&lt;/code&gt; in the namespace declaration, even with &lt;code&gt;:aot&lt;/code&gt;, the JVM won't find the entry point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Only in the Uberjar Profile?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:uberjar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:aot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; ← AOT everything for production jar&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AOT has downsides in development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower build — compiling everything takes time&lt;/li&gt;
&lt;li&gt;Stale classes — if you change code, old .class files can cause confusing bugs&lt;/li&gt;
&lt;li&gt;Bigger output — more files in target/&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>leiningen</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Clojure core.async: A Question &amp; Answer Journey on Channels</title>
      <dc:creator>ivan.gavlik</dc:creator>
      <pubDate>Fri, 13 Mar 2026 14:29:49 +0000</pubDate>
      <link>https://dev.to/ivangavlik/clojure-coreasync-a-question-answer-journey-on-channels-3om0</link>
      <guid>https://dev.to/ivangavlik/clojure-coreasync-a-question-answer-journey-on-channels-3om0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;core.async&lt;/code&gt; is Clojure's library for writing concurrent code without dealing with locks, callbacks, or complex threading.&lt;/p&gt;

&lt;p&gt;Write asynchronous code that looks synchronous. Your code reads top-to-bottom, even though operations happen concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Channels&lt;/strong&gt;: queues that connect producers and consumers. They hold data temporarily and coordinate when to send and receive values &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operations&lt;/strong&gt;: Non-blocking and blocking put and take operations for sending and receiving data &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Go block&lt;/strong&gt;: Place where you write sequential-looking async code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This post focuses exclusively on &lt;strong&gt;Channels&lt;/strong&gt;. We'll explore Operations (&amp;gt;!, &amp;lt;!, &amp;gt;!!, &amp;lt;!!) and Go blocks in the next posts.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Channels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What exactly is a channel?
&lt;/h3&gt;

&lt;p&gt;A channel is much more than a simple queue—it's a &lt;strong&gt;coordination mechanism&lt;/strong&gt; that manages communication between independent processes&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Internal Structure:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Every channel maintains four key components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Buffer&lt;/strong&gt;: Optional fixed-size queue holding values in transit. Can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nil&lt;/code&gt; (unbuffered - rendezvous semantics)&lt;/li&gt;
&lt;li&gt;Fixed buffer (bounded queue)&lt;/li&gt;
&lt;li&gt;Sliding buffer (drops oldest when full)&lt;/li&gt;
&lt;li&gt;Dropping buffer (drops newest when full)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Take Queue&lt;/strong&gt;: List of consumers waiting to receive values (when buffer is empty)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Put Queue&lt;/strong&gt;: List of producers waiting to send values (when buffer is full)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closed Flag + Lock&lt;/strong&gt;: Thread-safe state management for the channel lifecycle&lt;/p&gt;

&lt;h3&gt;
  
  
  How data flow in the channel internal structure?
&lt;/h3&gt;

&lt;p&gt;When you put a value on a channel, the implementation checks if any consumers are waiting. If so, the value is handed directly to a waiting consumer. If not, the value goes into the buffer (if there's space), or the producer joins the put queue to wait.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clojure.core.async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:refer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;&amp;gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go-loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;close!&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Unbuffered channel - producers and consumers must rendezvous&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unbuffered-ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Fixed buffer - can hold up to 10 values before blocking producers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffered-ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Sliding buffer - drops oldest values when full&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sliding-ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;a/sliding-buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Dropping buffer - drops newest values when full&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dropping-ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;a/dropping-buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Demonstration of buffer behavior&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Buffer size 2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Goes into buffer immediately&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Goes into buffer immediately&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Put two values"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Blocks here - buffer full, no consumer&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Put third value"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Thread/sleep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Let producer run&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"First value:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; 1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Second value:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; 2&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Third value:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; 3 - now producer can complete&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Output:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Put two values&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; First value: 1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Second value: 2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Put third value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Third value: 3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is diff between buffered vs unbuffered channels?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Buffered channel&lt;/strong&gt; = A mailbox where you can drop letters (items stored until someone picks them up).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unbuffered channel&lt;/strong&gt; = Handing something directly to someone (requires both people present at the same time).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unbuffered channels have no storage capacity.&lt;/strong&gt; They cannot hold any items at all.&lt;br&gt;
When you do (chan) with no buffer size, you create a channel with a buffer size of 0. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A producer trying to put a value must wait until a consumer is ready to take it&lt;/li&gt;
&lt;li&gt;A consumer trying to take a value must wait until a producer is ready to give it&lt;/li&gt;
&lt;li&gt;The value passes directly from producer to consumer in a "handshake" (No values are ever stored in the channel itself)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;:&lt;br&gt;
Both buffered and unbuffered channels work with all four operations: &lt;code&gt;&amp;gt;!&lt;/code&gt;, &lt;code&gt;&amp;lt;!&lt;/code&gt;, &lt;code&gt;&amp;gt;!!&lt;/code&gt;, &lt;code&gt;&amp;lt;!!&lt;/code&gt;&lt;br&gt;
The difference is in &lt;strong&gt;when blocking/parking happens&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buffered: Only blocks/parks when buffer is full (for puts) or empty (for takes)&lt;/li&gt;
&lt;li&gt;Unbuffered: Always blocks/parks until handoff completes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What are use cases for buffered and unbuffered channels?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Buffered Channels Use case&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm putting this in the queue for you to get to it when you can.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When producers generate data in bursts but consumers process steadily (e.g., user clicking buttons  rapidly, but backend processes one request at a time).&lt;/li&gt;
&lt;li&gt;When you want to queue up work without blocking the producer (e.g., logging system that accepts messages quickly while writing to disk happens in background)&lt;/li&gt;
&lt;li&gt;Email Queue: Marketing system generates 10,000 emails instantly when campaign launches, but email server can only send 100 per minute. Buffer stores the emails while they're sent gradually.&lt;/li&gt;
&lt;li&gt;Restaurant Order System: Kitchen receives orders in bursts during lunch rush (10 orders in 2 minutes, then nothing for 5 minutes). Buffer holds the orders so they're not lost, and kitchen processes them steadily.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Unbuffered Channels Use case&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you need confirmation that data was received before continuing (e.g., a worker acknowledging it accepted a task)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Worker Task Assignment: A manager hands work to a team member and waits until they confirm "I've got it" before walking away. You don't want to assume they took the task—you need to see them accept it.&lt;/li&gt;
&lt;li&gt;Database Transaction Coordination: Service A completes a database write and must wait for Service B to acknowledge it read the data before A can proceed. Both must be synchronized at that exact moment.&lt;/li&gt;
&lt;li&gt;Checkout Process: Customer submits payment, and the system must wait for payment gateway to confirm receipt before showing "Order Placed." Can't just fire-and-forget.&lt;/li&gt;
&lt;li&gt;Handshake Protocols: Two systems establishing a connection—client sends "hello," waits for server to respond "hello back" before proceeding. Each step requires mutual acknowledgment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What happens when a channel closes?
&lt;/h3&gt;

&lt;p&gt;Closing a channel signals "no more values will ever be sent." This is the standard way to communicate completion in core.async pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantics&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closed channels immediately return &lt;code&gt;nil&lt;/code&gt; to all consumers&lt;/li&gt;
&lt;li&gt;Attempts to put on a closed channel return &lt;code&gt;false&lt;/code&gt; (or throw in blocking operations)&lt;/li&gt;
&lt;li&gt;You can still drain values that were buffered before the close&lt;/li&gt;
&lt;li&gt;Closing is idempotent—closing an already-closed channel is safe
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Producer sends values then closes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;close!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Channel closed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;;; Attempting to put on closed channel&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Put after close returned:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; false&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Consumer loops until channel closes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go-loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if-some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Received:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Channel closed, exiting"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Output:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Received: 1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Received: 2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Received: 3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Channel closed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Put after close returned: false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Channel closed, exiting&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Critical pattern&lt;/strong&gt;: Use &lt;code&gt;if-some&lt;/code&gt; or &lt;code&gt;when-some&lt;/code&gt; to distinguish between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nil&lt;/code&gt; because channel closed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nil&lt;/code&gt; as an actual value (though sending &lt;code&gt;nil&lt;/code&gt; is discouraged)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Proper close detection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go-loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;when-some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; Continues only if val is non-nil&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;;; Loop exits when channel returns nil (closed)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Cleanup and shutdown"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Channels are coordination mechanisms&lt;/strong&gt;, not just queues. They manage the flow of data between independent processes.                          &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose your buffer type wisely&lt;/strong&gt;:                                                                                                             &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unbuffered: When you need rendezvous/handshake semantics
&lt;/li&gt;
&lt;li&gt;Fixed buffer: For backpressure and controlled queuing
&lt;/li&gt;
&lt;li&gt;Sliding buffer: When newest data matters most (like sensor readings)
&lt;/li&gt;
&lt;li&gt;Dropping buffer: When you can afford to lose data under load
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Always close channels&lt;/strong&gt; when production is complete. This is how consumers know to stop waiting.                                              &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;if-some&lt;/code&gt;/&lt;code&gt;when-some&lt;/code&gt;&lt;/strong&gt; to properly detect channel closure versus nil values.                                                             &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buffered channels decouple producers and consumers&lt;/strong&gt; in time, while unbuffered channels force synchronization.                                &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Now that you understand how channels work internally and when to use different buffer types, the next post will dive into &lt;strong&gt;Operations&lt;/strong&gt;:          &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The difference between parking (&lt;code&gt;&amp;gt;!&lt;/code&gt;, &lt;code&gt;&amp;lt;!&lt;/code&gt;) and blocking (&lt;code&gt;&amp;gt;!!&lt;/code&gt;, &lt;code&gt;&amp;lt;!!&lt;/code&gt;) operations
&lt;/li&gt;
&lt;li&gt;When to use each operation type
&lt;/li&gt;
&lt;li&gt;How &lt;code&gt;go&lt;/code&gt; blocks enable efficient concurrent programming
&lt;/li&gt;
&lt;li&gt;Composing channels with &lt;code&gt;alts!&lt;/code&gt;, &lt;code&gt;mult&lt;/code&gt;, &lt;code&gt;pub/sub&lt;/code&gt;, and pipelines
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Clojure Inheritance… Sort Of</title>
      <dc:creator>Paula Gearon</dc:creator>
      <pubDate>Thu, 12 Mar 2026 05:49:43 +0000</pubDate>
      <link>https://dev.to/quoll/clojure-inheritance-sort-of-2i6i</link>
      <guid>https://dev.to/quoll/clojure-inheritance-sort-of-2i6i</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;I want to start off by saying that I don't expect anyone to read this. However, neither OpenAI nor Anthropic's models get this right on the first try, so I figure that writing about it might get picked up in future training runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inheritance
&lt;/h2&gt;

&lt;p&gt;A pattern that I sometimes want in Clojure is to implement the same function for multiple types (defined by either &lt;code&gt;defrecord&lt;/code&gt; or &lt;code&gt;deftype&lt;/code&gt;). A simple way to do this is to do the work in an external function, and then have every implementation call it.&lt;/p&gt;

&lt;p&gt;For instance, say I want to get a list of feet from several animal types. I can create a protocol for this, with the function &lt;code&gt;get-feet&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Get a sequence of feet"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I may have a few different groups of animals, each sharing a number of feet. I can create a function for each of these groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-2-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-4-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-6-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="no"&gt;:middle-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-right&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the different record types will call the function they need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-2-feet&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-2-feet&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-4-feet&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-6-feet&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and so on.&lt;/p&gt;

&lt;p&gt;This works, but it is very unsatisfying. It also gets noisy if the protocol has more than one function.&lt;/p&gt;

&lt;p&gt;Instead, it would be nice if we could implement the protocol once, and then inherit this in any type that needs that implementation. Clojure doesn't support inheritance like this, but it has something close.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocols
&lt;/h2&gt;

&lt;p&gt;A Protocol in Clojure is a set of functions that an object has agreed to support. The language and compiler have special dispatch support around protocols, making their functions fast and easy to call. While many people know the specifics of protocols, this often comes about through exploration rather than documentation. I won't go into an exhaustive discussion of protocols here, but I will mention a couple of important aspects.&lt;/p&gt;

&lt;p&gt;Whenever a protocol is created in Clojure, two things are created: the protocol itself, and a plain-old Java Interface. (ClojureScript also has protocols, but they don't create interfaces). The protocol is just a normal data structure, which we can see at a repl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Get a sequence of feet"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user.Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:on-interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user.Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:sigs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-feet,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:arglists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Get a sequence of feet"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:method-map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:method-builders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user$eval143$fn__144&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x67001148&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"user$eval143$fn__144@67001148"&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This describes the protocol, and each of the associated functions. This is also the structure that gets modified by some of the various protocol extension macros. You may see how the &lt;code&gt;:method-map&lt;/code&gt; refers to functions by their name, rewritten as a keywords.&lt;/p&gt;

&lt;p&gt;Of interest here is the reference to the interface &lt;code&gt;user.Footed&lt;/code&gt;. I'm using a repl with the default &lt;code&gt;user&lt;/code&gt; namespace. Because we are already in this namespace, that &lt;code&gt;Footed&lt;/code&gt; interface name is being shadowed by the protocol object. But it is still there, and we can still do things with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Operations
&lt;/h2&gt;

&lt;p&gt;Protocols are often "extended" onto new datatypes. This is a very flexible operation, and allows new behavior to be associated with any datatype, including those not declared in Clojure (for instance, new behavior could be added to a &lt;code&gt;java.util.String&lt;/code&gt;). This applies to Interfaces as well as Classes, which is something we can use here.&lt;/p&gt;

&lt;p&gt;First of all, we want a new protocol/interface for each type of behavior that we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These protocols don't need functions, as they just serve to "mark" the objects that want to implement the desired behavior.&lt;/p&gt;

&lt;p&gt;Next, we can extend the protocol with our functions onto the types described by each of these Interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extend-protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user.Feet2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user.Feet4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user.Feet6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going back to the &lt;code&gt;Footed&lt;/code&gt; protocol, we can see that it now knows about these implementations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user.Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:on-interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user.Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:sigs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get-feet,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:arglists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Get a sequence of feet"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/Footed,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:method-map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:method-builders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user$eval143$fn__144&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x67001148&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"user$eval143$fn__144@67001148"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="no"&gt;:impls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;user.Feet2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user$eval195$fn__196&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x24fabd0f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"user$eval195$fn__196@24fabd0f"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;user.Feet4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user$eval199$fn__200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x250b236d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"user$eval199$fn__200@250b236d"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;user.Feet6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user$eval203$fn__204&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x61f3fbb8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"user$eval203$fn__204@61f3fbb8"&lt;/span&gt;&lt;span class="p"&gt;]}}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how the &lt;code&gt;:impls&lt;/code&gt; value now maps each of the extended interfaces to the attached functions.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Comment on Identifiers
&lt;/h4&gt;

&lt;p&gt;You might have noticed that I had to use the fully-qualified name for these interfaces due to the protocol name shadowing them. When a protocol is not in the same namespace, then it can be &lt;code&gt;require&lt;/code&gt;d, and referenced by its namespace, while the Interface can be &lt;code&gt;import&lt;/code&gt;ed from that namespace. For instance, a project that I've been working on recently has require/imports of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my.project&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;quoll.rdf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdf&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;quoll.rdf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IRI&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example I am able to reference the protocol via &lt;code&gt;rdf/IRI&lt;/code&gt; while the interface is just &lt;code&gt;IRI&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attaching
&lt;/h2&gt;

&lt;p&gt;Now that the &lt;code&gt;Footed&lt;/code&gt; protocol has been extended to each of these interfaces, the protocols associated with those interfaces can be attached to any type that wants that behavior.&lt;/p&gt;

&lt;p&gt;Going back to our animals, we can do the same thing again, but this time without the stub functions that redirect to the common functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instances of these types will now pick up the implementations extended to these marker protocols:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magilla&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Ape.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Magilla"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;big-bird&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Bird.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Big"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;garfield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Cat.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Garfield"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atom-ant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Ant.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Atom"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magilla&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;big-bird&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;garfield&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atom-ant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Declarations
&lt;/h2&gt;

&lt;p&gt;After explaining so much of the mechanism, the code has been scattered widely across this post. Putting the declarations together, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defprotocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extend-protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Footed&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="n"&gt;user.Feet2&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="n"&gt;user.Feet4&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="n"&gt;user.Feet6&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-feet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:front-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:front-right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:middle-right&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:back-left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:back-right&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defrecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Feet6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Functional programming in Clojure is not generally served by having multiple types like this, but it does happen. While this is a trivial example, with only a single function on the protocol, the need for this pattern becomes apparent when protocols come with multiple functions.&lt;/p&gt;

&lt;p&gt;I've called it inheritance, but that is only an analogy. It's not actually inheritance that we are applying here, but it does behave in a similar way.&lt;/p&gt;

</description>
      <category>clojure</category>
    </item>
    <item>
      <title>Just What IS Clojure, Anyway?</title>
      <dc:creator>Dimension AI Technologies</dc:creator>
      <pubDate>Sun, 08 Mar 2026 17:44:46 +0000</pubDate>
      <link>https://dev.to/dimension-ai/just-what-is-clojure-anyway-42np</link>
      <guid>https://dev.to/dimension-ai/just-what-is-clojure-anyway-42np</guid>
      <description>&lt;p&gt;Look at this line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;processCustomerOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any developer with six months of experience knows roughly what that does. The name is explicit, the structure is familiar, the intent is readable. Now look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reaction most developers have is immediate and unfavourable. Parentheses everywhere. No obvious structure. It looks less like a programming language and more like a typographer's accident. The old joke writes itself: LISP stands for Lost In Stupid Parentheses.&lt;/p&gt;

&lt;p&gt;That joke is, technically, a backronym. John McCarthy named it LISP as a contraction of &lt;em&gt;LISt Processing&lt;/em&gt; when he created it in 1958. The sardonic expansion came later, coined by programmers who had opinions about the aesthetic choices involved. Those opinions have not mellowed with time.&lt;/p&gt;

&lt;p&gt;And yet Clojure – a modern descendant of Lisp – ranked as one of the highest-paying languages in the Stack Overflow Developer Survey for several consecutive years around 2019. Developers walked away from stable Java and C# positions to build production systems in it. A Brazilian fintech used it to serve tens of millions of customers. Something requires explaining.&lt;/p&gt;




&lt;h2&gt;
  
  
  The ancestry: Lisp reborn
&lt;/h2&gt;

&lt;p&gt;Clojure only makes sense against the background of Lisp, and Lisp only makes sense as what it actually was: not merely a programming language, but a direct implementation of mathematical ideas about computation.&lt;/p&gt;

&lt;p&gt;McCarthy's 1958 creation introduced concepts that took the rest of the industry decades to absorb. Garbage collection, conditional expressions, functional programming, symbolic computation – all present in Lisp before most working developers today were born. Many programmers encounter Lisp's descendants daily without being aware of it.&lt;/p&gt;

&lt;p&gt;The defining feature is the S-expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is written as a list. This is not merely a syntactic preference. Because code and data share the same underlying structure, a Lisp program can manipulate other programs directly. This property – &lt;em&gt;homoiconicity&lt;/em&gt; – is the technical foundation of Lisp macros: code that generates and transforms other code at compile time, with a flexibility that few conventional infix languages match. It is the reason serious Lisp practitioners regard the syntax not as a historical curiosity but as a genuine technical advantage.&lt;/p&gt;

&lt;p&gt;Lisp also, however, developed a reputation for producing work that individual experts could write brilliantly and teams could not maintain at all. The tension between expressive power and collective readability never fully resolved. Clojure inherits this tradition knowingly, and is aware of the cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Clojure actually is
&lt;/h2&gt;

&lt;p&gt;The brilliant Rich Hickey created Clojure in 2007. His central design decision was not to build a new runtime from scratch but to attach Lisp to an existing ecosystem.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;JVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Libraries&lt;/td&gt;
&lt;td&gt;Java ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language model&lt;/td&gt;
&lt;td&gt;Lisp&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This host strategy gave Clojure immediate access to decades of mature Java libraries without needing to rebuild any of them. A Clojure developer can call Java code directly. The same logic drove two later variants: ClojureScript, which compiles to JavaScript and found real traction in teams already working with React, and ClojureCLR, which runs on .NET. Rather than fight the unwinnable battle of building its own ecosystem from scratch, Clojure attached itself to three of the largest ones that already existed.&lt;/p&gt;

&lt;p&gt;Clojure does not attempt to displace existing ecosystems. It operates inside them.&lt;/p&gt;

&lt;p&gt;Central to how Clojure development actually works is the REPL – Read–Eval–Print Loop. Rather than the standard write–compile–run–crash cycle, developers send code fragments to a running system and modify it live. Functions are redefined while the application continues executing. For experienced practitioners this is a material productivity difference: the feedback loop is short, and the distance between an idea and a tested result is small. Experienced Clojure developers report unusually low defect rates, a claim that is plausible given the constraints immutability places on the ways a programme can fail.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hickey doctrine: simple versus easy
&lt;/h2&gt;

&lt;p&gt;Hickey's 2011 Strange Loop talk &lt;em&gt;Simple Made Easy&lt;/em&gt; is the philosophical engine behind every design choice in Clojure. It draws a distinction that most language design ignores.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Familiar; close to what you already know&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Not intertwined; concerns kept separate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most languages pursue &lt;em&gt;easy&lt;/em&gt;. They aim to resemble natural language, minimise cognitive friction at the point of learning, and reduce the effort required to write the first working programme. This also means that languages favoured by human readers tend to be the hardest for which to write parsers and compilers.&lt;/p&gt;

&lt;p&gt;Clojure instead pursues &lt;em&gt;simple&lt;/em&gt;. Its goal is to minimise tangled interdependencies in the resulting system, even at the cost of an unfamiliar surface. Writing parsers for Lisps is comparatively straightforward, at the cost of human readability.&lt;/p&gt;

&lt;p&gt;Hickey's specific target is what he calls place-oriented programming: the treatment of variables as named locations in memory whose values change over time – mutability, in more formal terms. His argument is that conflating a &lt;em&gt;value&lt;/em&gt; with a &lt;em&gt;location&lt;/em&gt; generates incidental complexity at scale, particularly in concurrent systems. When you cannot be certain what a variable contains at a given moment, reasoning about a programme becomes difficult in proportion to the programme's size.&lt;/p&gt;

&lt;p&gt;The design of Clojure follows directly from this diagnosis. Immutable data, functional composition, minimal syntax, and data structures in place of object hierarchies are all consequences of the same underlying position. The language may not feel easy. The resulting systems are intended to be genuinely simpler to reason about.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real innovation: data and immutability
&lt;/h2&gt;

&lt;p&gt;Clojure's core model is data-oriented. Rather than building class hierarchies, programmes pass simple structures through functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:city&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"London"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new map. The original is untouched. That is the default behaviour across all of Clojure's data structures – values do not change; new versions are produced instead.&lt;/p&gt;

&lt;p&gt;This is made practical by &lt;em&gt;persistent data structures&lt;/em&gt;, which use structural sharing. When a new version of a data structure is produced, it shares most of its internal memory with the previous version rather than copying it entirely. The comparison that makes this intuitive for most developers: Git does not delete your previous commits when you push a new one. It stores only the difference, referencing unchanged content from before. Clojure applies the same principle to in-memory data.&lt;/p&gt;

&lt;p&gt;The consequence for concurrency results directly from this. Race conditions require mutable shared state. If data cannot be mutated, the precondition for the most common class of concurrency bug does not exist. This was Clojure's most compelling practical argument during the multicore boom of the 2010s, when writing correct concurrent code had become a routine industrial concern rather than a specialist one. Clojure let developers eliminate that entire class of problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The functional programming wave – and why easy beat rigorous
&lt;/h2&gt;

&lt;p&gt;Between roughly 2012 and 2020, functional programming moved from academic discussion to genuine industry interest. The drivers were concrete: multicore processors created pressure to write concurrent code correctly; distributed data systems required reasoning about transformation pipelines rather than mutable state; and the sheer complexity of large-scale software made the promise of mathematical rigour appealing.&lt;/p&gt;

&lt;p&gt;Clojure was among the most visible representatives of this movement, alongside Haskell, Scala, and F#. Conference talks filled. Engineering blogs ran long series on immutability and monads. For a period it seemed plausible that functional languages might displace the mainstream ones.&lt;/p&gt;

&lt;p&gt;What actually happened was different. Mainstream languages absorbed the useful ideas and continued. And the majority of working programmers, it turned out, rarely needed to reason about threading and concurrency at all.&lt;/p&gt;

&lt;p&gt;Java gained streams and lambdas in Java 8. JavaScript acquired map, filter, and reduce as first-class patterns, and React popularised unidirectional data flow. C# extended its functional capabilities across successive versions. Rust built immutability and ownership into its type system from the outset. The industry did not convert to functional programming – it extracted what it needed and kept the syntax it already knew.&lt;/p&gt;

&lt;p&gt;A developer who can obtain most of functional programming's benefits inside a language they already know will rarely conclude that switching entirely is justified.&lt;/p&gt;

&lt;p&gt;The deeper reason functional languages lost the mainstream argument is not technical. It is sociological. Python won because it is, in the most precise sense, the Visual Basic of the current era. That comparison is not an insult – Visual Basic dominated the 1990s because it made programming accessible to people who had no intention of becoming professional developers, and that accessibility produced an enormous, self-reinforcing community. Python did exactly the same thing for data scientists, academics, hobbyists, and beginners, and for precisely the same reason: it is easy to learn, forgiving of error, and immediately rewarding to write. Network effects took care of the rest. Libraries multiplied. Courses proliferated. Employers specified it. The ecosystem became self-sustaining.&lt;/p&gt;

&lt;p&gt;Clojure is the antithesis of this process. It is a language for connoisseurs – genuinely, not dismissively. Its internal consistency is elegant, its theoretical foundations are sound, and developers who master it frequently describe it with something approaching aesthetic appreciation. Mathematical beauty, however, has never been a reliable route to mass adoption. Narrow appeal does not generate network effects. And Clojure, by design, operates as something of a lone wolf: it rides atop the JVM rather than integrating natively with the broader currents of modern computing – the web-first tooling, the AI infrastructure, the vast collaborative ecosystems built around Python and JavaScript. At a moment when the decisive advantages in software development come from connectivity, interoperability, and the accumulated weight of shared tooling, a language that demands a clean break from everything a developer already knows is swimming directly against the tide.&lt;/p&gt;

&lt;p&gt;Compare this with Kotlin or TypeScript, both of which succeeded in part because they offered a graduated path. A developer new to Kotlin can write essentially Java-style code and improve incrementally. A developer new to TypeScript can begin with plain JavaScript and add types as confidence grows. Both languages have, in effect, a beginner mode. Clojure has no such thing. You either think in Lisp or you do not write Clojure at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Clojure succeeded
&lt;/h2&gt;

&lt;p&gt;Despite remaining a specialist language, Clojure has real industrial presence.&lt;/p&gt;

&lt;p&gt;The most prominent example is Nubank, a Brazilian fintech that reached a valuation of approximately $45 billion at its NYSE listing in December 2021. Nubank runs significant portions of its backend in Clojure, and in 2020 acquired Cognitect – the company that stewards the language. That acquisition was considerably more than a gesture; it was a statement of long-term commitment from an organisation operating at scale.&lt;/p&gt;

&lt;p&gt;ClojureScript found parallel influence in the JavaScript ecosystem. The Reagent and re-frame frameworks attracted serious production use, demonstrating that the Clojure model could be applied to front-end development at scale and not merely to backend data pipelines.&lt;/p&gt;

&lt;p&gt;The pattern that emerges from successful Clojure deployments is consistent: small, experienced teams working on data-intensive systems where correctness and concurrency matter more than onboarding speed. That is a narrow niche. It was also, not coincidentally, a well-paid one – for a time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verdict: the ideas won
&lt;/h2&gt;

&lt;p&gt;Clojure despite its brilliance and initial buzz has not become a mainstream language. By any measure of adoption – survey rankings, job advertisements, GitHub repositories – it remains firmly in specialist territory. Even F#, a functional rival with the full weight of Microsoft's backing - and easier syntax - has not broken through.&lt;/p&gt;

&lt;p&gt;But the arguments Clojure made in 2007 has largely been vindicated. Immutability is now a design principle in Rust, Swift, and Kotlin. Functional composition is standard across modern JavaScript and C#. Data-oriented design has become an explicit architectural pattern in game development and systems programming. The industry did not adopt Clojure, but it has been grateful for Hickey's ideas and has in fact hungrily absorbed them.&lt;/p&gt;

&lt;p&gt;What did not transfer was the syntax – and behind the syntax lay an economic problem that no philosophical vindication could resolve.&lt;/p&gt;

&lt;p&gt;Developers and Heads of Technology might love Clojure for its expressive power and productivity. But a CTO and their C-suite peers evaluating a language does not ask only whether it is technically sound. The questions are: how large is the available talent pool? How long does onboarding take? What happens when a key developer leaves? Does it leave us exposed to key person risk? Clojure's answers to all of these questions are uncomfortable.&lt;/p&gt;

&lt;p&gt;There is a further cost that rarely appears in language comparisons. A developer with ten years of experience in Java, C#, or Python carries genuine accumulated capital: hard-won familiarity with idioms, libraries, failure modes, and tooling. Switching to a Lisp-derived language does not extend that knowledge – it resets it. Clojure keeps the JVM underneath but discards almost everything a developer has learned about how to structure solutions idiomatically. The ten-year veteran spends their first six months feeling like a junior again. Recursion replaces loops. Immutable pipelines replace stateful objects. The mental models that took years to build are, at best, partially transferable. They might even fail entirely to transition to functional thinking, after decades in imperative and OOP styles.  That cost and those risks are real and largely invisible in adoption discussions, and they fall on precisely the experienced developers an organisation most wants to retain. Knowledge compounds most effectively when it is built upon incrementally. Clojure does not permit that. It demands a clean break, and most organisations and most developers are not willing to pay that price.&lt;/p&gt;

&lt;p&gt;The high wages Clojure commanded were not, from a management perspective, a straightforward mark of quality. They were a warning of risk, of "god programmer" lock-in. They reflected something less flattering than productivity: the classic dynamic of the expert who becomes indispensable by writing systems that only they can maintain. At its worst this approaches a form of institutional capture – a codebase so entangled with one person's idiom that replacing them becomes prohibitively expensive, something uncomfortably close to ransomware in its commercial effect.&lt;/p&gt;

&lt;p&gt;That position has been further undermined by the rise of agentic coding tools. The practical value of writing in a mainstream language has dramatically increased, because AI coding assistants are trained on the accumulated body of code that exists – and that body is overwhelmingly Python, JavaScript, Java, and C#. The effect is concrete: ask a capable model to produce a complex data transformation in Python and it draws on an enormous foundation of high-quality examples. Ask it to do the same in idiomatic Clojure and the results are less reliable, the suggestions thinner, the tooling shallower. It might have to go through several rounds of trial-and-error. A language's effective learnability in 2026 is no longer a matter only of human cognition; it is also a function of training density. Niche languages are niche in the training data too, and that gap compounds. The expert moat – already questionable on organisational grounds – is being drained from two directions at once.&lt;/p&gt;

&lt;p&gt;Clojure's ideas spread widely and rapidly through the languages that absorbed them and left the parentheses behind. Its practitioners, once among the best-paid developers in the industry, now find that the scarcity premium they commanded rested partly on barriers that no longer hold.&lt;/p&gt;




&lt;p&gt;So, just what is Clojure, anyway? It is a language that was correct about the most important questions in software design, arrived a decade before the industry was ready to hear the answers, and expressed those answers in a notation the industry was not willing to learn.&lt;/p&gt;

&lt;p&gt;The language was right about the future of programming. It might not be part of that future now that it has arrived. But it rightly deserves a place in computing history.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is part of an ongoing series examining what programming languages actually are and why they matter.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/dimension-ai/why-c-is-still-the-most-important-programming-language-2n9j"&gt;C&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The irreplaceable foundation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/dimension-ai/just-what-is-python-anyway-7ce"&gt;Python&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The approachable language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/dimension-zero/just-what-is-rust-anyway-28bh"&gt;Rust&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Safe systems programming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clojure&lt;/td&gt;
&lt;td&gt;Powerful ideas, niche language&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Coming next: Zig, Odin, and Nim – three languages that think C's job could be done better, and have very different ideas about how.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
    </item>
    <item>
      <title>Datastar Observations</title>
      <dc:creator>Howard M. Lewis Ship</dc:creator>
      <pubDate>Sat, 07 Feb 2026 23:35:22 +0000</pubDate>
      <link>https://dev.to/hlship/datastar-observations-3icg</link>
      <guid>https://dev.to/hlship/datastar-observations-3icg</guid>
      <description>&lt;p&gt;I've been very impressed, so far, with &lt;a href="https://data-star.dev" rel="noopener noreferrer"&gt;Datastar&lt;/a&gt;, a tiny JavaScript library for front-end work; I've been switching a &lt;a href="https://github.com/hlship/dialog-tool" rel="noopener noreferrer"&gt;personal side-project&lt;/a&gt; from using &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; for it's UI to Datastar, and as amazing as Svelte is, Datastar has impressed me more.&lt;/p&gt;

&lt;p&gt;Datastar's essential concept is for the client to shift virtually all logic and all markup rendering back to the server; event handlers can succinctly call server endpoints, which return markup, and the markup is morphed into the running DOM. This makes the server-side is the system of record. Datastar has a nice DSL, based on &lt;code&gt;data-*&lt;/code&gt; attributes, allowing you to do nearly anything you need to do in the client, declaratively.&lt;/p&gt;

&lt;p&gt;Alternately, the server can start an SSE (server sent event) stream and send down markup to morph into the DOM, or JavaScript to execute, over any period of time. For example, my project has a long running process and it was a snap to create a modal progress dialog and keep it updated as the server-side process looped through its inputs.&lt;/p&gt;

&lt;p&gt;The mantra of Datastar is to &lt;em&gt;trust the morph and the browser&lt;/em&gt; -- it's surprisingly fast to update even when sending a fair bit of content. It feels wasteful to update a whole page just to change a few small things (say, mark a button as disabled) but it works, and it's fast, and it frees you from a nearly all client-side reactive updates (and all the related edge cases and unforseen consequences).&lt;/p&gt;

&lt;p&gt;The server side is not bound to any particular language or framework (they have API implementations for Clojure, Java, Python, Ruby, and many others) ... and you could probably write your own API in an afternoon.&lt;/p&gt;

&lt;p&gt;I especially like side-stepping the issue of needing more representations of data; the data lives server-side, all that is ever sent to the client is markup. There's no over-the-wire representation, and no parallel client-side data model. All that's ever exposed as endpoints are intentional ones that do work and deliver markup ... in other words, always use-case based, never schema based. &lt;/p&gt;

&lt;p&gt;There's a minimal amount of reactive logic in the client, but the essence of moving the logic to server feels like home; Tapestry (way back in 2005) had some similar ideas, but was far more limited (due to many factors, including JavaScript and browser maturity in that time).&lt;/p&gt;

&lt;p&gt;I value simplicity, and Datastar looks to fit my needs without doing so much that is magical or hidden. I consider that a big win!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>clojure</category>
    </item>
    <item>
      <title>No, Clojure: your REPL is not new – or best</title>
      <dc:creator>Dimension AI Technologies</dc:creator>
      <pubDate>Sat, 20 Dec 2025 11:07:34 +0000</pubDate>
      <link>https://dev.to/dimension-ai/no-clojure-your-repl-is-not-new-or-best-556</link>
      <guid>https://dev.to/dimension-ai/no-clojure-your-repl-is-not-new-or-best-556</guid>
      <description>&lt;p&gt;Spend any time around &lt;a href="https://en.wikipedia.org/wiki/Clojure" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;'s devoted community and you'll encounter a cluster of claims:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Read–Eval–Print Loop ("REPL") is what makes Clojure fundamentally different (&lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;REPL – Wikipedia&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;REPL-driven development supersedes the Edit–Compile–Run model typical of C-family, .NET and Java&lt;/li&gt;
&lt;li&gt;Clojure enables a uniquely live, exploratory way of building systems&lt;/li&gt;
&lt;li&gt;other languages "don't really have a REPL"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These claims sound radical, historically grounded and quietly superior, but they are – alas – more rhetoric than fact.&lt;/p&gt;

&lt;p&gt;This article challenges established wisdom about Clojure in three areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the REPL long predates Clojure&lt;/li&gt;
&lt;li&gt;Clojure neither invented nor uniquely exemplifies it&lt;/li&gt;
&lt;li&gt;several alternative REPL models outperform Clojure's on important engineering criteria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be clear, Clojure is a powerful language with dedicated supporters; so what follows is not an attack on Clojure, but a suggestion that its mythology needs a tweak.&lt;/p&gt;




&lt;h2&gt;
  
  
  The REPL long predates Clojure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lisp had already established the model by 1958
&lt;/h3&gt;

&lt;p&gt;The Read–Eval–Print Loop originates in Lisp systems developed at MIT in the late 1950s (&lt;a href="https://en.wikipedia.org/wiki/History_of_Lisp" rel="noopener noreferrer"&gt;History of Lisp – Wikipedia&lt;/a&gt;). From the outset, Lisp environments supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interactive evaluation&lt;/li&gt;
&lt;li&gt;incremental definition of functions&lt;/li&gt;
&lt;li&gt;inspection and modification of live runtime state&lt;/li&gt;
&lt;li&gt;persistent sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The terminology itself has a long and well-documented history. The expression &lt;em&gt;"read–eval–print cycle"&lt;/em&gt; is used by L. Peter Deutsch and Edmund Berkeley in a 1964 implementation of Lisp on the PDP-1 (&lt;a href="https://softwarepreservation.computerhistory.org/projects/LISP/book/III_LispBook_Apr66.pdf" rel="noopener noreferrer"&gt;Deutsch &amp;amp; Berkeley, 1964&lt;/a&gt;). Just one month later, Project MAC published a report by Joseph Weizenbaum — later known as the creator of ELIZA, the world's first chatbot — describing a REPL-based language, OPL-1, implemented in his Fortran-SLIP language on the Compatible Time Sharing System (CTSS) (&lt;a href="https://dspace.mit.edu/handle/1721.1/149332" rel="noopener noreferrer"&gt;Weizenbaum, 1964&lt;/a&gt;; &lt;a href="https://en.wikipedia.org/wiki/Compatible_Time-Sharing_System" rel="noopener noreferrer"&gt;CTSS – Wikipedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;By 1974, the &lt;em&gt;Maclisp Reference Manual&lt;/em&gt; by David A. Moon explicitly refers to a &lt;em&gt;"read-eval-print loop"&lt;/em&gt; (page 89), even though the acronym "REPL" is not yet used (&lt;a href="https://www.softwarepreservation.org/projects/LISP/MIT/Moon-MACLISP_Reference_Manual-Apr_08_1974.pdf" rel="noopener noreferrer"&gt;Moon, 1974&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;From at least the early 1980s onward, the abbreviations &lt;em&gt;REP loop&lt;/em&gt; and &lt;em&gt;REPL&lt;/em&gt; are attested in the context of Scheme, where the term became standard (&lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;Scheme REPL terminology history&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Clojure deliberately situates itself within this lineage and explicitly inherits from it.&lt;/p&gt;

&lt;p&gt;Once that inheritance is acknowledged, the oft-claimed notion that the REPL distinguishes Clojure needs correction. Any feature drawn wholesale from a sixty-year-old tradition cannot serve as a defining innovation.&lt;/p&gt;




&lt;h3&gt;
  
  
  ML: a typed REPL from the early 1970s
&lt;/h3&gt;

&lt;p&gt;Alongside Lisp, the original ML language — developed in the early 1970s as part of the Edinburgh LCF project (&lt;a href="https://en.wikipedia.org/wiki/Logic_for_Computable_Functions" rel="noopener noreferrer"&gt;LCF – Wikipedia&lt;/a&gt;) — was explicitly designed for interactive use.&lt;/p&gt;

&lt;p&gt;ML's REPL supported incremental definition, immediate evaluation and full static type inference at the prompt. This was not an afterthought. ML was a &lt;em&gt;metalanguage&lt;/em&gt;, intended to be explored live while retaining formal guarantees.&lt;/p&gt;

&lt;p&gt;This matters because it shows that REPL-driven development under strong static typing is not a modern compromise or a reaction against Lisp. It is a parallel tradition, older than Clojure by decades.&lt;/p&gt;




&lt;h3&gt;
  
  
  Smalltalk pushed live systems further in the 1970s
&lt;/h3&gt;

&lt;p&gt;Smalltalk systems went beyond REPL interaction and embraced image-based development (&lt;a href="https://en.wikipedia.org/wiki/Smalltalk" rel="noopener noreferrer"&gt;Smalltalk – Wikipedia&lt;/a&gt;), where the entire system existed as a continuously mutable artefact. Programs were edited while running; the notion of a clean restart receded into the background.&lt;/p&gt;

&lt;p&gt;This approach predates Clojure by decades and represents a more radical commitment to liveness than Clojure's own model.&lt;/p&gt;

&lt;p&gt;However one judges Smalltalk today, its existence alone undermines the idea that live, interactive programming is a modern breakthrough.&lt;/p&gt;




&lt;h3&gt;
  
  
  Home computers normalised persistent REPLs
&lt;/h3&gt;

&lt;p&gt;The most consequential historical counterexample is neither Lisp nor Smalltalk. It is home computing.&lt;/p&gt;

&lt;p&gt;From the late 1970s through the mid-1980s, the overwhelming majority of home computers booted directly into a persistent BASIC environment (&lt;a href="https://en.wikipedia.org/wiki/BASIC" rel="noopener noreferrer"&gt;BASIC – Wikipedia&lt;/a&gt;). Immediate mode was the primary interface. Variables survived &lt;code&gt;RUN&lt;/code&gt;. Programs routinely relied on pre-initialised state in order to function within severe memory constraints.&lt;/p&gt;

&lt;p&gt;This behaviour was universal and far from exceptional.&lt;/p&gt;

&lt;h4&gt;
  
  
  Home-computer BASIC: persistent REPL as the default interface
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Machine&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;BASIC variant&lt;/th&gt;
&lt;th&gt;Persistent variables&lt;/th&gt;
&lt;th&gt;Immediate mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TRS-80 Model I&lt;/td&gt;
&lt;td&gt;1977&lt;/td&gt;
&lt;td&gt;Microsoft BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commodore PET&lt;/td&gt;
&lt;td&gt;1977&lt;/td&gt;
&lt;td&gt;Microsoft BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple II&lt;/td&gt;
&lt;td&gt;1977&lt;/td&gt;
&lt;td&gt;Applesoft BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atari 400/800&lt;/td&gt;
&lt;td&gt;1979&lt;/td&gt;
&lt;td&gt;Atari BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZX-80&lt;/td&gt;
&lt;td&gt;1980&lt;/td&gt;
&lt;td&gt;Sinclair BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIC-20&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;td&gt;Commodore BASIC 2.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZX-81&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;td&gt;Sinclair BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BBC Model A&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;td&gt;BBC BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BBC Model B&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;td&gt;BBC BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZX Spectrum&lt;/td&gt;
&lt;td&gt;1982&lt;/td&gt;
&lt;td&gt;Sinclair BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commodore 64&lt;/td&gt;
&lt;td&gt;1982&lt;/td&gt;
&lt;td&gt;Commodore BASIC 2.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dragon 32/64&lt;/td&gt;
&lt;td&gt;1982–83&lt;/td&gt;
&lt;td&gt;Microsoft BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oric-1&lt;/td&gt;
&lt;td&gt;1983&lt;/td&gt;
&lt;td&gt;Oric Extended BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amstrad CPC&lt;/td&gt;
&lt;td&gt;1984&lt;/td&gt;
&lt;td&gt;Locomotive BASIC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tens of millions of machines shipped with precisely this interaction model.&lt;/p&gt;

&lt;p&gt;Rather than being an esoteric Lisp technique rediscovered decades later, the "tight feedback loop" was simply how personal computing worked for an entire generation. Many senior industry figures learned their craft in that world.&lt;/p&gt;

&lt;p&gt;It is also worth noting that the BASIC world itself once abandoned the interactive model it had popularised. Early BASIC systems treated the programming environment as a live, persistent session. With the move to Visual Basic and later VB.NET (&lt;a href="https://en.wikipedia.org/wiki/Visual_Basic_(classic)" rel="noopener noreferrer"&gt;Visual Basic – Wikipedia&lt;/a&gt;; &lt;a href="https://en.wikipedia.org/wiki/Visual_Basic_.NET" rel="noopener noreferrer"&gt;VB.NET – Wikipedia&lt;/a&gt;), that model gave way to an IDE-centred, project-based workflow, where code was edited, built and executed as a discrete artefact.&lt;/p&gt;

&lt;p&gt;This shifted BASIC from language-as-environment to language-as-artifact.&lt;/p&gt;

&lt;p&gt;Interactivity did not vanish entirely, but it moved from the language to the tooling, and the REPL ceased to be the organising centre.&lt;/p&gt;




&lt;h3&gt;
  
  
  Erlang demonstrated live code in production
&lt;/h3&gt;

&lt;p&gt;To argue that Clojure uniquely enables live mutation of running systems means overlooking Erlang, the telecoms language created by Ericsson (&lt;a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)" rel="noopener noreferrer"&gt;Erlang – Wikipedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;From the late 1980s onward, Erlang supported hot code swapping in safety-critical telephony infrastructure. Far from exploratory hacking, this was production engineering under strict uptime requirements.&lt;/p&gt;

&lt;p&gt;Live systems were already operational long before Clojure appeared.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Clojure actually contributes
&lt;/h2&gt;

&lt;p&gt;Clojure's achievement lies elsewhere.&lt;/p&gt;

&lt;p&gt;It brings together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Lisp REPL tradition&lt;/li&gt;
&lt;li&gt;the JVM ecosystem&lt;/li&gt;
&lt;li&gt;persistent data structures (&lt;a href="https://en.wikipedia.org/wiki/Persistent_data_structure" rel="noopener noreferrer"&gt;Persistent data structure – Wikipedia&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;modern concurrency primitives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This synthesis is real and valuable, and the result of thoughtful engineering.&lt;/p&gt;

&lt;p&gt;Interactive programming and the REPL itself, however, sit firmly in the inherited category.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real trade-off: semantic mutability
&lt;/h2&gt;

&lt;p&gt;The distinctive characteristic of Clojure's REPL is not persistence per se, but the level at which persistence operates.&lt;/p&gt;

&lt;p&gt;Early BASIC systems preserved data. Numbers, arrays and flags survived across runs. Control flow remained linear, and program meaning remained fixed.&lt;/p&gt;

&lt;p&gt;Clojure extends persistence to meaning. Functions may be redefined live. Dispatch rules can be altered. Existing call sites can acquire new behaviour without any obvious signpost.&lt;/p&gt;

&lt;p&gt;This shift increases expressive power, but the engineering bill arrives as reduced reconstructability and predictability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clojure: silent semantic drift
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Session start: define calculate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/calculate&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Later, perhaps in another file or by another developer:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; silently replaces original&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;'user/calculate&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;user=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; No warning. No error. Source file unchanged.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a single developer, this is simply a useful tool. In a team, it becomes a coordination hazard: runtime truth can drift away from the text everyone believes they are running.&lt;/p&gt;




&lt;h2&gt;
  
  
  On Rich Hickey's position
&lt;/h2&gt;

&lt;p&gt;In talks such as &lt;em&gt;Simple Made Easy&lt;/em&gt; (&lt;a href="https://www.infoq.com/presentations/Simple-Made-Easy/" rel="noopener noreferrer"&gt;InfoQ video&lt;/a&gt;) and various discussions of REPL-driven development, Rich Hickey has argued that interactive development should be central, while edit–compile–run should be viewed as inefficient.&lt;/p&gt;

&lt;p&gt;The intuition behind this argument is understandable. Iteration speed matters.&lt;/p&gt;

&lt;p&gt;The framing, however, tends to obscure two facts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interactive development long predates Clojure&lt;/li&gt;
&lt;li&gt;many systems combine interactivity with compilation discipline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Growing systems live accelerates exploration, but it also erodes the ability to reconstruct behaviour from source alone. That trade-off deserves to be stated explicitly.&lt;/p&gt;

&lt;p&gt;Hickey did not claim the REPL was new. The Clojure community, however, often treats it as a unique truth.&lt;/p&gt;




&lt;h2&gt;
  
  
  A structural comparison
&lt;/h2&gt;

&lt;p&gt;A clearer perspective emerges from comparing REPL models across history.&lt;/p&gt;

&lt;p&gt;Legend: ✅ Yes, ❌ No, 🟡 Limited&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;1958–60: Lisp REPL (image-based)&lt;/th&gt;
&lt;th&gt;1964: Dartmouth BASIC&lt;/th&gt;
&lt;th&gt;1977–85: Home BASIC&lt;/th&gt;
&lt;th&gt;1973–: ML / OCaml REPL&lt;/th&gt;
&lt;th&gt;2005–: F# REPL&lt;/th&gt;
&lt;th&gt;2007–: Clojure REPL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Interactive evaluation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immediate mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistent session&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variables persist across runs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First-class functions&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live function redefinition&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌*&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Behavioural semantics mutable live&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static type checking&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type system constrains REPL&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silent semantic mutation possible&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reconstructable from source alone&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Designed for long-lived systems&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;BBC BASIC excepted; most home BASICs lacked named functions and relied on line-numbered subroutines.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A counterexample: the ML lineage (OCaml and F#)
&lt;/h2&gt;

&lt;p&gt;F# is not an outlier. It belongs to a lineage – ML and OCaml (&lt;a href="https://en.wikipedia.org/wiki/OCaml" rel="noopener noreferrer"&gt;OCaml – Wikipedia&lt;/a&gt;) – that has treated interactive, typed REPL-driven development as normal practice for over forty years.&lt;/p&gt;

&lt;p&gt;F#'s REPL chooses constraint over maximal dynamism, but the mechanism deserves to be described accurately.&lt;/p&gt;

&lt;p&gt;F# allows shadowing with a new binding. When type signatures match, however, F# offers no protection against semantic drift – the same 'silent mutation' problem exists as in Clojure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// F#: type system provides no protection when signatures match&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;   &lt;span class="c1"&gt;// same signature, different semantics&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;105&lt;/span&gt;
&lt;span class="c1"&gt;// Same silent semantic drift as Clojure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is that F#'s type system provides &lt;em&gt;partial&lt;/em&gt; protection: it prevents one class of errors (type mismatches at call sites) but not semantic changes within the same type. When a function is redefined with a different type signature, the type system catches inconsistent usage at the point of application, forcing the programmer to address the incompatibility explicitly.&lt;/p&gt;

&lt;p&gt;For teams that value refactoring, long-term maintenance and source-level truth, this partial discipline often proves advantageous – though it does not eliminate the reconstructability problem entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  "But Clojure's REPL is integrated"
&lt;/h2&gt;

&lt;p&gt;A predictable rebuttal points to tooling: CIDER (&lt;a href="https://cider.mx" rel="noopener noreferrer"&gt;https://cider.mx&lt;/a&gt;), nREPL (&lt;a href="https://nrepl.org" rel="noopener noreferrer"&gt;https://nrepl.org&lt;/a&gt;) and editor integration.&lt;/p&gt;

&lt;p&gt;Better tools improve the experience. They do not alter the underlying model, which remains rooted in a design first implemented in the 1950s.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the mythology persists
&lt;/h2&gt;

&lt;p&gt;The persistence of the REPL myth is easy to explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lisp culture has always emphasised interactivity&lt;/li&gt;
&lt;li&gt;computing history before the web is poorly remembered&lt;/li&gt;
&lt;li&gt;expressive power is often confused with novelty&lt;/li&gt;
&lt;li&gt;difficulty is frequently mistaken for depth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this indicates bad faith, but it does reward clearer framing.&lt;/p&gt;

&lt;p&gt;This transition took place more than a generation ago. As a consequence, the interactive environments that once defined everyday programming gradually slipped from the memory of both enthusiasts and professionals. Later rediscoveries of REPL-driven workflows were then easily mistaken for innovations rather than revivals.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The REPL is an immensely valuable tool. Its lineage stretches back more than six decades. Clojure's indisputable power rests heavily on it, but that power arrives through inheritance rather than invention.&lt;/p&gt;

&lt;p&gt;Other languages explore the same design space differently, sometimes with stronger engineering constraints.&lt;/p&gt;

&lt;p&gt;It is also worth noting a structural echo. REPL-driven workflows treat programming as a dialogue rather than a batch process, and today's agent-driven coding tools adopt a similar stance. They extend the conversational model from interaction with a running &lt;em&gt;program&lt;/em&gt; to interaction with an entire &lt;em&gt;codebase&lt;/em&gt;. It would be a stretch to claim a direct causal link, but the resemblance is clear: both approaches reject the assumption that code must be "finished" before it can be tested against reality.&lt;/p&gt;

&lt;p&gt;Clojure's REPL offers power and has made a great deal of noise. It has reinvigorated an old paradigm and delighted its community. Power is not, however, novelty; and enthusiasm must not rewrite history.&lt;/p&gt;




&lt;h2&gt;
  
  
  Acknowledgments
&lt;/h2&gt;

&lt;p&gt;Thanks to Frank Adrian for pointing out that the original F# example compared type-system differences rather than REPL-model differences. The corrected example now shows how F#, like Clojure, permits silent semantic drift when function signatures remain unchanged; the F# type system provides only partial protection against this class of error.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Read–Eval–Print Loop (REPL) – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;History of Lisp – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/History_of_Lisp" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/History_of_Lisp&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;L. Peter Deutsch &amp;amp; Edmund Berkeley, &lt;em&gt;LISP on the PDP-1&lt;/em&gt; (1964)&lt;br&gt;
&lt;a href="https://softwarepreservation.computerhistory.org/projects/LISP/book/III_LispBook_Apr66.pdf" rel="noopener noreferrer"&gt;https://softwarepreservation.computerhistory.org/projects/LISP/book/III_LispBook_Apr66.pdf&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Joseph Weizenbaum, &lt;em&gt;OPL-1 on CTSS&lt;/em&gt; (1964)&lt;br&gt;
&lt;a href="https://dspace.mit.edu/handle/1721.1/149332" rel="noopener noreferrer"&gt;https://dspace.mit.edu/handle/1721.1/149332&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatible Time-Sharing System (CTSS) – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Compatible_Time-Sharing_System" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Compatible_Time-Sharing_System&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;David A. Moon, &lt;em&gt;Maclisp Reference Manual&lt;/em&gt; (1974)&lt;br&gt;
&lt;a href="https://www.softwarepreservation.org/projects/LISP/MIT/Moon-MACLISP_Reference_Manual-Apr_08_1974.pdf" rel="noopener noreferrer"&gt;https://www.softwarepreservation.org/projects/LISP/MIT/Moon-MACLISP_Reference_Manual-Apr_08_1974.pdf&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scheme REPL terminology history&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edinburgh LCF – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Edinburgh_LCF" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Edinburgh_LCF&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smalltalk – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Smalltalk" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Smalltalk&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BASIC – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/BASIC" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/BASIC&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Visual Basic (classic) – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Visual_Basic_(classic)" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Visual_Basic_(classic)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VB.NET – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Visual_Basic_.NET" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Visual_Basic_.NET&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Erlang (programming language) – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Erlang_(programming_language)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Persistent data structure – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Persistent_data_structure" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Persistent_data_structure&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rich Hickey, &lt;em&gt;Simple Made Easy&lt;/em&gt; (InfoQ video)&lt;br&gt;
&lt;a href="https://www.infoq.com/presentations/Simple-Made-Easy/" rel="noopener noreferrer"&gt;https://www.infoq.com/presentations/Simple-Made-Easy/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OCaml – Wikipedia&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/OCaml" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/OCaml&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CIDER&lt;br&gt;
&lt;a href="https://cider.mx" rel="noopener noreferrer"&gt;https://cider.mx&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;nREPL&lt;br&gt;
&lt;a href="https://nrepl.org" rel="noopener noreferrer"&gt;https://nrepl.org&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>clojure</category>
      <category>readevaluateprintloop</category>
      <category>programminghistory</category>
      <category>basic</category>
    </item>
    <item>
      <title>What it was like to give a talk at Clojure South 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Wed, 03 Dec 2025 14:45:59 +0000</pubDate>
      <link>https://dev.to/marciofrayze/what-it-was-like-to-give-a-talk-at-clojure-south-2025-b1c</link>
      <guid>https://dev.to/marciofrayze/what-it-was-like-to-give-a-talk-at-clojure-south-2025-b1c</guid>
      <description>&lt;h2&gt;
  
  
  What is Clojure South?
&lt;/h2&gt;

&lt;p&gt;According to the &lt;a href="http://clojure-south.com" rel="noopener noreferrer"&gt;official website&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Organized by Nubank, Clojure South is part of the official Clojure community schedule, connecting developers, enthusiasts, and companies to share real experiences, discuss trends, and strengthen the global network of the language." - Translated from Brazilian Portuguese by me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In a conversation with a Brazilian woman I met at &lt;a href="https://www.lambdadays.org/lambdadays2025" rel="noopener noreferrer"&gt;Lambda Days 2025&lt;/a&gt; (I talked about what it was like to attend this event &lt;a href="https://dev.to/marciofrayze/how-was-my-experience-at-lambda-days-2025-2kc2"&gt;in this article&lt;/a&gt;), I asked if she would attend the conference (she works at Nubank) and found out she would be an instructor for the Clojure workshop. During this conversation, she suggested that I should submit a talk proposal. I mentioned an idea I had in mind but was feeling a bit insecure about sending it. She encouraged me to try, and I decided to take a chance!&lt;/p&gt;

&lt;p&gt;Although I already have &lt;a href="(https://segunda.tech/about)"&gt;some talks&lt;/a&gt; on my resume, I felt that maybe I should be more cautious in this case, and submit a proposal for a &lt;em&gt;lightning talk&lt;/em&gt; (a 10-minute talk with no time for questions).&lt;/p&gt;

&lt;p&gt;A few weeks later, to my surprise, the proposal was accepted!&lt;/p&gt;

&lt;h2&gt;
  
  
  Theme
&lt;/h2&gt;

&lt;p&gt;I had two possible topics in mind. One about teaching Clojure and Functional Programming to beginners (because of my course &lt;a href="https://segunda.tech/clojure" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;; an Introduction to Functional Programming through Clojure, for Brazilians). And another about a project I built at the company where I work, using Clojure in the &lt;em&gt;backend&lt;/em&gt; and the programming language &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; for the &lt;em&gt;front-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I chose the second one. It was already a project I wanted to talk about publicly, and this seemed like a great opportunity!&lt;/p&gt;

&lt;p&gt;Another factor is that the project is related to a very well-known App in Brazil, the Digital Driver's License — an &lt;em&gt;App&lt;/em&gt; developed by &lt;a href="https://www.serpro.gov.br" rel="noopener noreferrer"&gt;SERPRO&lt;/a&gt; and available for &lt;a href="https://play.google.com/store/apps/details?id=br.gov.serpro.cnhe" rel="noopener noreferrer"&gt;Android&lt;/a&gt; and &lt;a href="https://apps.apple.com/br/app/carteira-digital-de-tr%C3%A2nsito/id1275057217" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;. I imagined this could increase the chances of the talk being accepted.&lt;/p&gt;

&lt;p&gt;The full description I submitted was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;During the development of the &lt;em&gt;Carteira Digital de Trânsito&lt;/em&gt; (Digital Driver's License), I realized how challenging it was to support an App with millions of users integrated with many systems. I dreamed of creating a simple, friendly internal interface for queries that would make support easier. That’s how &lt;strong&gt;&lt;em&gt;Apoio CDT&lt;/em&gt;&lt;/strong&gt; was born, a web system that automated processes and enabled fast and secure queries. With a Clojure backend and an Elm front-end, we developed an MVP in three weeks. The result was a simple, efficient, and easy-to-maintain web architecture over the years.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As far as I know, this was the company’s first project using Clojure and also the first using Elm. And it was the first time I had the opportunity to talk about this system to people outside the company where I work!&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Talks and Workshops
&lt;/h2&gt;

&lt;p&gt;The event lasted two days, and the first day featured the two workshops:&lt;/p&gt;

&lt;h3&gt;
  
  
  Clojure Workshop
&lt;/h3&gt;

&lt;p&gt;An introductory Clojure course, in English, taught by &lt;a href="https://www.linkedin.com/in/christoph-neumann-6089438/" rel="noopener noreferrer"&gt;Christoph Neumann&lt;/a&gt;, Clojure &lt;em&gt;Developer Advocate&lt;/em&gt; at Nubank.&lt;/p&gt;

&lt;p&gt;Although I already have experience with Clojure, it was great to reinforce the main concepts of the language and I even learned some fundamentals I didn’t know yet!&lt;/p&gt;

&lt;h3&gt;
  
  
  Datomic Workshop
&lt;/h3&gt;

&lt;p&gt;The afternoon of the first day was dedicated to the &lt;em&gt;workshop&lt;/em&gt; of the &lt;a href="https://www.datomic.com" rel="noopener noreferrer"&gt;Datomic&lt;/a&gt; database. It was taught in Brazilian Portuguese by &lt;a href="https://www.linkedin.com/in/aanacarolina/" rel="noopener noreferrer"&gt;Carolina Silva&lt;/a&gt; (the same one I mentioned at the beginning of this article) and &lt;a href="https://www.linkedin.com/in/hanna-f-mariano-59578596/" rel="noopener noreferrer"&gt;Hanna Figueiredo&lt;/a&gt;, both &lt;em&gt;Software Engineers&lt;/em&gt; at Nubank.&lt;/p&gt;

&lt;p&gt;I had already watched several talks about Datomic and always found it an intriguing and interesting database. I believe it would make a lot of sense to use it in several projects I have worked on or currently work on.&lt;/p&gt;

&lt;p&gt;The workshop covered many theoretical concepts of Datomic, but it was also very hands-on.&lt;/p&gt;

&lt;p&gt;You can check out the hands-on portion of the workshop &lt;a href="https://github.com/Datomic/day-of-datomic-conj" rel="noopener noreferrer"&gt;in this GitHub repository&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I confess it was a lot of information in a short time. I will definitely need to revisit the repository and practice a lot more to internalize the core concepts of this database. But it was totally worth it!&lt;/p&gt;

&lt;p&gt;If before I already thought studying this database was worthwhile, now I’m certain of it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conversations and Feedback
&lt;/h2&gt;

&lt;p&gt;Right when I arrived at the event, I had the chance to talk to some people I only knew online, such as &lt;a href="https://www.linkedin.com/in/arthur-fucher/" rel="noopener noreferrer"&gt;Arthur Fücher&lt;/a&gt;. Besides being a &lt;em&gt;Senior Software Engineer&lt;/em&gt; at Nubank, Arthur is very active in the Brazilian Clojure community!&lt;/p&gt;

&lt;p&gt;And even though I am quite shy, I was able to meet many great people from Brazil and other countries.&lt;/p&gt;

&lt;p&gt;In particular, I was welcomed &lt;strong&gt;very&lt;/strong&gt; warmly by Christoph Neumann. I was standing quietly in a corner during the &lt;em&gt;happy hour&lt;/em&gt;, after the second day of the event, eating and thinking about heading home, when he approached me and started a conversation. We talked a bit, and I began asking a few questions about Datomic. During the conversation, I mentioned that Datomic might be a good fit for the company where I work. When I said what the company does, he became very interested! And soon offered to introduce me to &lt;a href="https://www.linkedin.com/in/joe-lane-7674173a/" rel="noopener noreferrer"&gt;Joe Lane&lt;/a&gt;, &lt;em&gt;Principal Engineer Building Datomic&lt;/em&gt; at Nubank!&lt;/p&gt;

&lt;p&gt;I talked to Joe and, again, was very kindly received! He seemed genuinely excited when I mentioned where I worked and the types of projects SERPRO develops, and he offered to answer any questions about Datomic — even mentioning that SERPRO could be a great Datomic case study.&lt;/p&gt;

&lt;p&gt;During the event, I also had the opportunity to meet people who took &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;my Clojure course&lt;/a&gt;! Among them, I met &lt;a href="https://www.linkedin.com/in/bruno-dobelin/" rel="noopener noreferrer"&gt;Bruno Guimarães&lt;/a&gt;, currently a &lt;em&gt;Senior Software Engineer&lt;/em&gt; at Nubank and the host of the conference.&lt;/p&gt;

&lt;p&gt;Meeting students of my online course in person is always a very special experience! The numbers, the stats, the comments — they gain a face, a voice, life. It's truly rewarding!&lt;/p&gt;

&lt;p&gt;On the second day, after my talk, many people came to talk and learn more about how I introduced Clojure into a federal government system in Brazil. Some had specific questions about my motivation for using &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; on the &lt;em&gt;front-end&lt;/em&gt; (instead of opting for ClojureScript), plus several other interesting conversations.&lt;/p&gt;

&lt;p&gt;The feedback was very positive, and all the conversations were friendly, fun, and respectful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Food (and More Conversations)
&lt;/h2&gt;

&lt;p&gt;The event had a &lt;em&gt;welcome coffee&lt;/em&gt; in the morning and &lt;em&gt;coffee breaks&lt;/em&gt; throughout the day. The quality was excellent and everything was quite formal (maybe a bit too formal? lol).&lt;/p&gt;

&lt;p&gt;For lunch, there were several options (not included in the ticket price) within the same building complex where &lt;a href="https://building.nubank.com/pt-br/escritorio-nubank-brasil-spark/" rel="noopener noreferrer"&gt;Nubank Sparks&lt;/a&gt; is located. This made things much easier, especially on the workshop day, since I had my laptop with me.&lt;/p&gt;

&lt;p&gt;You could eat wherever you wanted. But I liked the nearby options, and it became yet another opportunity to talk to more people from the event. Again, even being shy and sitting somewhere more secluded, several people soon came to sit with me and chat. At that moment, I met a Ukrainian attendee who showed us the &lt;em&gt;Diia&lt;/em&gt; App, where she can have digital versions of several documents such as her Driver’s License, Passport, and more — with access to over 130 government services (you can learn more about this App &lt;a href="https://en.wikipedia.org/wiki/Diia" rel="noopener noreferrer"&gt;on its Wikipedia page&lt;/a&gt;)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Was It Worth It?
&lt;/h2&gt;

&lt;p&gt;Definitely, yes!&lt;/p&gt;

&lt;p&gt;The event happened on two weekdays (a Monday and Tuesday). This may make it difficult for some people to attend — for example, a colleague of mine couldn’t go because his company didn’t allow him to take those days off. But for those who can attend, it’s far less tiring than having an event like this over the weekend after a long workweek.&lt;/p&gt;

&lt;p&gt;I had purchased the early-bird tickets before my talk was accepted, but later the event organizers refunded me — I received free tickets for both days as a speaker. They also offered help with transportation and lodging, which I declined since the event was close to where I live.&lt;/p&gt;

&lt;p&gt;The experience of speaking at an event of this magnitude, even if only for 10 minutes, was incredible! It’s a feeling of great gratitude to the people who organized the conference and who trusted in my potential!&lt;/p&gt;




&lt;p&gt;Did you like this article? &lt;strong&gt;Don't forget to leave a reaction!&lt;/strong&gt; They serve as a big incentive for me to write others.&lt;/p&gt;

&lt;p&gt;You can also discover more articles, podcasts and videos at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want, follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/marcio-frayze" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>nubank</category>
      <category>elm</category>
    </item>
    <item>
      <title>Como foi palestrar na Clojure South 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Sun, 23 Nov 2025 21:40:28 +0000</pubDate>
      <link>https://dev.to/marciofrayze/como-foi-palestrar-na-clojure-south-2025-3hb3</link>
      <guid>https://dev.to/marciofrayze/como-foi-palestrar-na-clojure-south-2025-3hb3</guid>
      <description>&lt;h2&gt;
  
  
  O que é a Clojure South?
&lt;/h2&gt;

&lt;p&gt;Segundo &lt;a href="http://clojure-south.com" rel="noopener noreferrer"&gt;site oficial&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Organizada pelo Nubank, a Clojure South faz parte da programação oficial da comunidade de Clojure, conectando pessoas desenvolvedoras, entusiastas e empresas para compartilhar experiências reais, discutir tendências e fortalecer a rede global da linguagem."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivação
&lt;/h2&gt;

&lt;p&gt;Em uma conversa com uma brasileira que conheci na &lt;a href="https://www.lambdadays.org/lambdadays2025" rel="noopener noreferrer"&gt;Lambda Days 2025&lt;/a&gt; (falei sobre como foi participar deste evento &lt;a href="https://dev.to/marciofrayze/como-foi-minha-experiencia-na-lambda-days-2025-27k3"&gt;neste artigo&lt;/a&gt;), perguntei se ela iria assistir às palestras (ela trabalha para a Nubank) e descobri que ela iria ser instrutora do &lt;em&gt;workshop&lt;/em&gt; de Clojure! Nesta conversa ela sugeriu que eu deveria enviar uma proposta de palestra. Comentei uma ideia que eu tinha para submeter, mas que estava meio inseguro de enviar. Ela me encorajou a tentar e eu resolvi arriscar!&lt;/p&gt;

&lt;p&gt;Embora tenha no meu currículo &lt;a href="(https://segunda.tech/sobre)"&gt;algumas palestras&lt;/a&gt; e &lt;a href="https://segunda.tech/tags/podcast/" rel="noopener noreferrer"&gt;participações em podcasts&lt;/a&gt;, sentia que talvez fosse mais interessante, neste caso, submeter uma proposta no formato &lt;em&gt;lighting talk&lt;/em&gt; (palestra de apenas 10 minutos e sem tempo para perguntas).&lt;/p&gt;

&lt;p&gt;E algum tempo depois, para minha surpresa, a proposta foi aceita!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tema
&lt;/h2&gt;

&lt;p&gt;Havia pensado em enviar propostas sobre dois possíveis temas. Um sobre o ensino de Clojure e Programação Funcional para iniciantes (por conta do meu curso &lt;a href="https://segunda.tech/clojure" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;). E outro sobre um projeto que fiz na empresa onde trabalho, que utiliza Clojure no &lt;em&gt;backend&lt;/em&gt; e a linguagem de programação &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; para o &lt;em&gt;front-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Optei pela segunda opção. Já era um projeto que eu queria falar sobre publicamente e esta parecia ser uma boa oportunidade! &lt;/p&gt;

&lt;p&gt;Outro fator é que o projeto em questão está relacionado com um &lt;em&gt;App&lt;/em&gt; bastante famoso no Brasil, a Carteira Digital de Trânsito — &lt;em&gt;App&lt;/em&gt; desenvolvido pelo &lt;a href="https://www.serpro.gov.br" rel="noopener noreferrer"&gt;SERPRO&lt;/a&gt; e disponível para &lt;a href="https://play.google.com/store/apps/details?id=br.gov.serpro.cnhe" rel="noopener noreferrer"&gt;Android&lt;/a&gt; e &lt;a href="https://apps.apple.com/br/app/carteira-digital-de-tr%C3%A2nsito/id1275057217" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;. Imaginava que isso poderia aumentar as chances de a palestra ser aceita.&lt;/p&gt;

&lt;p&gt;A descrição completa que enviei foi:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Durante o desenvolvimento da &lt;em&gt;Carteira Digital de Trânsito&lt;/em&gt;, percebi como era desafiador dar suporte a um &lt;em&gt;App&lt;/em&gt; com milhões de usuários integrado a diversos sistemas. Sonhei em criar uma interface interna simples e amigável para consultas que facilitassem o atendimento. Assim surgiu o &lt;strong&gt;Apoio CDT&lt;/strong&gt;, um sistema web que automatizou processos e permitiu consultas rápidas e seguras. Com &lt;em&gt;backend&lt;/em&gt; em Clojure e &lt;em&gt;front-end&lt;/em&gt; em Elm, desenvolvemos um MVP em três semanas. O resultado foi uma arquitetura web simples, eficiente e fácil de manter ao longo dos anos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Até onde sei, este foi o primeiro projeto da empresa que utilizada Clojure e também o primeiro a utilizar Elm. E esta foi a primeira vez que tive oportunidade de falar sobres este sistema para pessoas de fora da empresa onde trabalho!&lt;/p&gt;

&lt;h2&gt;
  
  
  Demais palestras e &lt;em&gt;workshops&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;O evento durou dois dias, sendo que no primeiro ocorreram os 2 &lt;em&gt;workshops&lt;/em&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Workshop&lt;/em&gt; de Clojure
&lt;/h3&gt;

&lt;p&gt;Um curso de introdução ao Clojure, em inglês, ministrado pelo &lt;a href="https://www.linkedin.com/in/christoph-neumann-6089438/" rel="noopener noreferrer"&gt;Christoph Neumann&lt;/a&gt;, &lt;em&gt;Developer Advocate&lt;/em&gt; de Clojure no Nubank.&lt;/p&gt;

&lt;p&gt;Embora eu já tenha experiência com Clojure (e inclusive seja instrutor do curso &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;), foi muito legal reforçar os principais conceitos desta linguagem e também aprendi alguns fundamentos que ainda não conhecia!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Workshop&lt;/em&gt; de Datomic
&lt;/h3&gt;

&lt;p&gt;O período da tarde do primeiro dia foi destinado ao &lt;em&gt;workshow&lt;/em&gt; do banco de dados &lt;a href="https://www.datomic.com" rel="noopener noreferrer"&gt;Datomic&lt;/a&gt;. Este foi ministrado em português pela &lt;a href="https://www.linkedin.com/in/aanacarolina/" rel="noopener noreferrer"&gt;Carolina Silva&lt;/a&gt; (a mesma que citei no começo deste artigo) e &lt;a href="https://www.linkedin.com/in/hanna-f-mariano-59578596/" rel="noopener noreferrer"&gt;Hanna Figueiredo&lt;/a&gt;, ambas &lt;em&gt;Software Engineering&lt;/em&gt; no Nubank.&lt;/p&gt;

&lt;p&gt;Eu já havia assistido várias palestras sobre o Datomic e sempre achei um banco de dados muito intrigante e interessante. Acredito que faria muito sentido utilizá-lo em vários dos projetos que atuo ou já atuei no passado.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;workshop&lt;/em&gt; mostrou vários conceitos teóricos do Datomic, mas também foi muito prático.&lt;/p&gt;

&lt;p&gt;Você pode conferir a parte prática do &lt;em&gt;workshop&lt;/em&gt; &lt;a href="https://github.com/Datomic/day-of-datomic-conj" rel="noopener noreferrer"&gt;neste repositório do GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Confesso que foi muitas informações em pouco tempo. Definitivamente, vou precisar voltar ao repositório e praticar bastante ainda para internalizar os principais conceitos deste banco de dados. Mas valeu muito a pena!&lt;/p&gt;

&lt;p&gt;Se antes eu achava que valeria a pena estudar este banco, agora tenho certeza!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conversas e &lt;em&gt;feedbacks&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Logo ao chegar no evento tive a oportunidade de conversar com algumas pessoas que só conhecia virtualmente, como o &lt;a href="https://www.linkedin.com/in/arthur-fucher/" rel="noopener noreferrer"&gt;Arthur Fücher&lt;/a&gt;. Além de ser &lt;em&gt;Senior Software Engineer&lt;/em&gt; no Nubank, Arthur é uma figura muito presente na comunidade Clojure do Brasil!&lt;/p&gt;

&lt;p&gt;E mesmo sendo uma pessoa bastante tímida, foi possível conhecer muitas pessoas bacanas do Brasil e de outros países.&lt;/p&gt;

&lt;p&gt;Em especial, fui &lt;strong&gt;muito&lt;/strong&gt; bem recebido pelo Christoph Neumann. Eu estava parado em um canto no &lt;em&gt;happy hour&lt;/em&gt;, após o segundo dia de evento, comendo e pensando em já ir pra casa, quando ele se aproximou e puxou conversa. Conversamos um pouco e comecei a fazer algumas perguntas sobre Datomic. Ao longo da conversa, citei que talvez fosse um banco de dados interessante para empresa onde trabalho. Quando falei onde trabalhava e o que a empresa fazia, ele se mostrou bastante interessado! E logo se ofereceu para me apresentar o &lt;a href="https://www.linkedin.com/in/joe-lane-7674173a/" rel="noopener noreferrer"&gt;Joe Lane&lt;/a&gt;, &lt;em&gt;Principal Engineer Building Datomic&lt;/em&gt; na Nubank!&lt;/p&gt;

&lt;p&gt;Conversei com o Joe e, mais uma vez, fui super bem recebido! Ele mostrou bastante entusiasmo quando comentei onde trabalhava e os tipos de projetos que o SERPRO desenvolve, e ficou à disposição para tirar dúvidas sobre Datomic, inclusive comentando que o SERPRO poderia ser um ótimo &lt;em&gt;case&lt;/em&gt; para o Datomic.&lt;/p&gt;

&lt;p&gt;Ao longo do evento também tive a oportunidade de conhecer algumas pessoas que fizeram &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;meu curso de Clojure&lt;/a&gt;! Entre essas pessoas, conheci o &lt;a href="https://www.linkedin.com/in/bruno-dobelin/" rel="noopener noreferrer"&gt;Bruno Guimarães&lt;/a&gt;, que atualmente é &lt;em&gt;Senior Software Engineer&lt;/em&gt; no Nubank e foi &lt;em&gt;host&lt;/em&gt; da conferência.&lt;/p&gt;

&lt;p&gt;Conhecer pessoalmente pessoas que fizeram meu curso online é sempre uma experiência muito legal! Os números, as estatísticas, os comentários, ganham um cara, uma voz, vida. É sempre muito gratificante!&lt;/p&gt;

&lt;p&gt;No segundo dia, após a minha apresentação, muitas pessoas vieram conversar e querer saber mais sobre como consegui introduzir Clojure em um sistema do governo federal brasileiro. Tiveram algumas dúvidas mais pontuais, sobre minha motivação para usar &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; no &lt;em&gt;front-end&lt;/em&gt; (e não optar por utilizar Clojure em sua versão &lt;a href="https://clojurescript.org" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;), entre várias outras conversas interessantes.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;feedback&lt;/em&gt; foi bastante positivo e todas as conversas foram muito bacanas, bem humoradas e respeitosas. &lt;/p&gt;

&lt;h2&gt;
  
  
  Comidas (e mais conversas)
&lt;/h2&gt;

&lt;p&gt;O evento contava com &lt;em&gt;welcome coffee&lt;/em&gt; no início do dia e &lt;em&gt;coffee breaks&lt;/em&gt; ao longo do dia. A qualidade era muito boa e tudo muito formal (talvez formal até um pouco demais? rs).&lt;/p&gt;

&lt;p&gt;Já para almoçar, existiam várias opções (não inclusas no valor do ingresso) de restaurantes dentro do mesmo complexo de prédios onde encontra-se a &lt;a href="https://building.nubank.com/pt-br/escritorio-nubank-brasil-spark/" rel="noopener noreferrer"&gt;Nubank Sparks&lt;/a&gt;. Isso facilitava bastante, já que não precisava sair do local, especialmente no primeiro dia, de workshops, já que estava com meu notebook.&lt;/p&gt;

&lt;p&gt;Você pode almoçar onde quiser. Mas gostei das opções que estavam disponíveis ali perto e foi mais uma oportunidade de conversar com mais pessoas do evento. Novamente, mesmo sendo bastante tímido e sentando em um lugar mais afastado, logo vieram várias pessoas sentar junto comigo e puxar conversa. Neste momento conheci uma Ucraniana que mostrou pra gente o App &lt;em&gt;Diia&lt;/em&gt;, onde ela pode ter versões digitais de vários de seus documentos, como Carteira de Motorista, Passaporte, entre outros e ter acesso a mais de 130 serviços do governo Ucraniano (você pode saber mais sobre este App &lt;a href="https://en.wikipedia.org/wiki/Diia" rel="noopener noreferrer"&gt;nesta página do Wikipedia&lt;/a&gt;)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Valeu a pena?
&lt;/h2&gt;

&lt;p&gt;Definitivamente, sim!&lt;/p&gt;

&lt;p&gt;O evento ocorreu em dois dias da semana (uma segunda e terça-feira). Isso talvez atrapalhe a participação de algumas pessoas — um colega meu não conseguiu participar pois a empresa não liberou este dias para ele, por exemplo. Mas para aquelas pessoas que conseguem participar, fica muito menos cansativo do que ter um evento como este no final de semana, depois de uma longa semana de trabalho.&lt;/p&gt;

&lt;p&gt;Eu havia comprado os ingressos na pré-venda, antes de ter minha palestra aprovada, mas depois tive o valor estornado pela coordenação do evento - ganhei ingressos para os dois dias por ser palestrante. Também me ofereceram ajuda para transporte e estadia, a qual eu recusei, já que o evento seria próximo da minha residência.&lt;/p&gt;

&lt;p&gt;A experiência de palestrar em um evento desta magnitude, mesmo que por apenas 10 minutos, foi incrível! É uma sensação de muita gratidão às pessoas que ajudaram a organizar a conferência e que confiaram no meu potencial!&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>programaçãofuncional</category>
      <category>nubank</category>
      <category>serpro</category>
    </item>
    <item>
      <title>Native Apps with ClojureScript, React and Static Hermes</title>
      <dc:creator>Roman Liutikov</dc:creator>
      <pubDate>Mon, 17 Nov 2025 16:00:00 +0000</pubDate>
      <link>https://dev.to/romanliutikov/native-apps-with-clojurescript-react-and-static-hermes-1ebg</link>
      <guid>https://dev.to/romanliutikov/native-apps-with-clojurescript-react-and-static-hermes-1ebg</guid>
      <description>&lt;p&gt;What you see in the demo below is ClojureScript &lt;a href="https://github.com/pitch-io/uix" rel="noopener noreferrer"&gt;UIx&lt;/a&gt; app driving native window with &lt;a href="https://github.com/ocornut/imgui" rel="noopener noreferrer"&gt;ImGui&lt;/a&gt; UI via custom React reconciler. Both hot-reloading and REPL-driven development are supported, as you'd expect it from a typical ClojureScript project.&lt;/p&gt;

&lt;p&gt;The JavaScript side of the app runs in &lt;a href="https://github.com/facebook/hermes" rel="noopener noreferrer"&gt;Hermes&lt;/a&gt; engine, which exposes ImGui to JS env. However, a release build of this exact app is a fully native 8MB executable. You can try it yourself on &lt;a href="https://github.com/roman01la/cljs-static-hermes/actions/runs/19209017328/artifacts/4511932229" rel="noopener noreferrer"&gt;macOS&lt;/a&gt; or &lt;a href="https://github.com/roman01la/cljs-static-hermes/actions/runs/19209017328/artifacts/4511972286" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;While Hermes engine is a JavaScript VM, it is also an AOT compiler for JavaScript that emits either Hermes byte code or C.&lt;/p&gt;

&lt;p&gt;Compiling this sample JavaScript program with Static Hermes: &lt;code&gt;shermes -emit-c index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs the following C program or 50KB executable, when compiled straight into a binary &lt;code&gt;shermes -Os index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_get_global_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_try_get_by_id_rjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_symbols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cm"&gt;/*print*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_read_prop_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_try_get_by_id_rjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_symbols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cm"&gt;/*globalThis*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_read_prop_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_get_by_id_rjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;get_symbols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cm"&gt;/*value*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_read_prop_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shUnit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;np0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_add_rjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;np0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1 + globalThis.value&lt;/span&gt;
&lt;span class="n"&gt;np0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_undefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_undefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_undefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sh_ljs_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_sh_leave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;np0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above demo is 8MB executable on macOS, where 3MB is Hermes runtime, 1.8MB is React the JavaScript library compiled to C and the rest 3.2MB goes to native libraries ImGui and libwebsockets, and ClojureScript code compiled to C.&lt;/p&gt;

&lt;p&gt;Here's a rough diagram of how things are bundled in the executable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.romanliutikov.com%2Fimgs%2Fcljs-hermes-arch.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.romanliutikov.com%2Fimgs%2Fcljs-hermes-arch.jpg" width="800" height="715"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may noticed there's &lt;em&gt;untyped&lt;/em&gt; and &lt;em&gt;typed&lt;/em&gt; JavaScript. When AOT compiling typed JavaScript, which can be a subset of either TypeScript or &lt;a href="https://flow.org/" rel="noopener noreferrer"&gt;Flow&lt;/a&gt;, Hermes emits a more optimal C making it suitable for performance sensitive code, such as bindings to native libraries runnning in a hot loop.&lt;/p&gt;

&lt;p&gt;As an example, compiling the following typed program with &lt;code&gt;-typed&lt;/code&gt; flag: &lt;code&gt;shermes -typed -emit-c index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;emits C that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;doesn’t create an &lt;code&gt;add&lt;/code&gt; function/closure, instead the arithmetic is emitted inline&lt;/li&gt;
&lt;li&gt;adds type assertion for unkown value &lt;code&gt;globalThis.value&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;includes fewer symbols &amp;amp; caches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check both typed and untyped C &lt;a href="https://gist.github.com/roman01la/bc65626625acb3b0ac6dfb960ef8beb7" rel="noopener noreferrer"&gt;here&lt;/a&gt;, here's also a &lt;a href="https://www.diffchecker.com/Zp0HIv30/" rel="noopener noreferrer"&gt;diff&lt;/a&gt; to make it more obvious.&lt;/p&gt;

&lt;p&gt;As I said earlier, the app runs raw JavaScript in dev to provide fast feedback loop and support interactive development. This is possible because Hermes has multiple tiers of code optimization:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;During developent JavaScript VM loads the code and emits byte code (JIT) at runtime&lt;/li&gt;
&lt;li&gt;You can also compile JavaScript to bytecode (.hbc file) ahead of time. This use case is quite popular in React Native, where application code is compiled into Hermes bytecode at build time to improve startup time of mobile apps, especially on Android.&lt;/li&gt;
&lt;li&gt;Finally, with Static Hermes you can compile JavaScript to native object file. This way you get statically linked machine code, skipping parsing and JIT.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the best part about this setup is actually React itself. I didn't have to change &lt;em&gt;anything&lt;/em&gt; in UIx to make it work with original &lt;a href="https://github.com/tmikov/imgui-react-runtime" rel="noopener noreferrer"&gt;imgui-react-runtime&lt;/a&gt; demo. The real power and a curse of React is that it is a platform independent abstraction. It's up to the host platform to provide specific realization of the contract. If you are Clojure developer, this might sound &lt;a href="https://clojure.org/reference/data_structures#:~:text=Collections%20are%20represented%20by%20abstractions%2C%20and%20there%20may%20be%20one%20or%20more%20concrete%20realizations." rel="noopener noreferrer"&gt;familiar&lt;/a&gt; to you.&lt;/p&gt;

&lt;p&gt;The abstraction in question is React's &lt;a href="https://github.com/facebook/react/tree/main/packages/react-reconciler" rel="noopener noreferrer"&gt;reconciler&lt;/a&gt;. By implementing its interface you can create custom render targets, such as React Native, &lt;a href="https://react.pixijs.io/" rel="noopener noreferrer"&gt;PixiJS React&lt;/a&gt;, &lt;a href="https://github.com/pmndrs/react-three-fiber" rel="noopener noreferrer"&gt;react-three-fiber&lt;/a&gt;, you can even create &lt;a href="https://github.com/vadimdemedes/ink" rel="noopener noreferrer"&gt;Terminal UIs&lt;/a&gt; and &lt;a href="https://github.com/diegomura/react-pdf" rel="noopener noreferrer"&gt;PDFs&lt;/a&gt; with it. Heck, if you take a step back and think about the reconciler as a generic abstraction for turning declarative description of something into a set of imperative operations, you can even &lt;a href="https://iamdustan.com/react-hardware/" rel="noopener noreferrer"&gt;run hardware&lt;/a&gt; with it.&lt;/p&gt;

&lt;p&gt;Ok, so how fast is AOT compiled JavaScript with Static Hermes? Here's a quick benchmark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;simple-benchmark&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;odd?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;zipmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;repeatedly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math/random&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;repeatedly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math/random&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;take&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;mapcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;identity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optimized executable runs for ~6450 ms. Same code executed as JavaScript in Node and Bun runs for ~1100 ms. That's 6x slower, ouch. On the bright side, the executable is just a few MBs, while embedding JS VM will get you at least up to 60MB in the case of Bun. If you ask me, I'll always prefer 6x faster app, doesn't matter how big it is.&lt;/p&gt;

&lt;p&gt;However, the case with React is quite specific. React being a declarative abstraction on top of imperative APIs almost always means that hot code paths are executed in underlying layers, whether it's browser's DOM, mobile views, WebGL or ImGui. And often times you have an option to use that lower level, more performant API directly, when needed.&lt;/p&gt;

&lt;p&gt;Hermes was originally developed for React Native and mobile apps, with a focus on improving startup performance. Even generated native code &lt;a href="https://github.com/facebook/hermes/discussions/1685#discussioncomment-12938461" rel="noopener noreferrer"&gt;can't compete&lt;/a&gt; with JITs in modern JavaScript engines.&lt;/p&gt;

&lt;p&gt;Bonus point. Similarly to how &lt;a href="https://github.com/thheller/shadow-cljs" rel="noopener noreferrer"&gt;shadow-cljs&lt;/a&gt; displays compiler warnings and errors in a browser, the demo ImGui app also captures and displays warnings and errors, as well as includes an error boundary component that catches runtime exceptions thrown during render phase.&lt;/p&gt;



&lt;p&gt;Checkout the code of this project at &lt;a href="https://github.com/roman01la/cljs-static-hermes" rel="noopener noreferrer"&gt;roman01la/cljs-static-hermes&lt;/a&gt;, which is based off the work done by a member of Hermes team, at &lt;a href="https://github.com/tmikov/imgui-react-runtime" rel="noopener noreferrer"&gt;tmikov/imgui-react-runtime&lt;/a&gt;. If you are interested in driving native window from runtimes like Node or Bun, checkout this project showcasing use of &lt;a href="https://bun.com/docs/runtime/ffi" rel="noopener noreferrer"&gt;Bun's FFI&lt;/a&gt; to interface with &lt;a href="https://www.glfw.org/" rel="noopener noreferrer"&gt;GLFW&lt;/a&gt; and OpenGL: &lt;a href="https://github.com/roman01la/hra" rel="noopener noreferrer"&gt;roman01la/hra&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>clojure</category>
      <category>clojurescript</category>
      <category>hermes</category>
    </item>
    <item>
      <title>Advanced Beginner’s guide to ClojureScript</title>
      <dc:creator>Roman Liutikov</dc:creator>
      <pubDate>Fri, 07 Nov 2025 20:00:00 +0000</pubDate>
      <link>https://dev.to/romanliutikov/advanced-beginners-guide-to-clojurescript-oi2</link>
      <guid>https://dev.to/romanliutikov/advanced-beginners-guide-to-clojurescript-oi2</guid>
      <description>&lt;p&gt;So how does your tiny ClojureScript program transform into runnable JavaScript?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Howdy!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, you need a compiler! ClojureScript is a hosted language, which means you have to compile it into JavaScript, unless you want to ship the compiler into a browser to be able to interpret ClojureScript at runtime, which is slow and in most cases doesn't make sense (but maybe you wanna build online REPL, that's ok).&lt;/p&gt;

&lt;p&gt;This is not going to be easy. ClojureScript sits on top of JavaScript, the compiler is a library written in Clojure, which in turn hosts on JVM. This means you need Java installed, huh.&lt;/p&gt;

&lt;p&gt;I prefer to use &lt;a href="https://sdkman.io/" rel="noopener noreferrer"&gt;sdkman&lt;/a&gt; to manage my Java installations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdk &lt;span class="nb"&gt;install &lt;/span&gt;java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to install Clojure, head over to &lt;a href="https://clojure.org/guides/install_clojure" rel="noopener noreferrer"&gt;installation guide at clojure.org&lt;/a&gt;. If the following command returns &lt;code&gt;2&lt;/code&gt;, you are good!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"(inc 1)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create project directory somewhere and put &lt;code&gt;deps.edn&lt;/code&gt; file into it with the following contents. &lt;code&gt;deps.edn&lt;/code&gt; is kind of &lt;code&gt;package.json&lt;/code&gt;, if you are coming from JavaScript world.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojurescript&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.12.42"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you have Node installed? Now we can run ClojureScript REPL in Node environment. This line runs JVM process that loads Clojure, that loads ClojureScript compiler, starts Node process and runs it in REPL mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; cljs.main &lt;span class="nt"&gt;--target&lt;/span&gt; node &lt;span class="nt"&gt;--repl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this runs, it means you are hooked into Node process, nice!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;js/console.log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try to list files in the current directory using Node'js &lt;code&gt;fs&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;js/require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"fs"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.readdirSync&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"./"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works? Great, let's move onto actually compiling a project into JavaScript files. Put our tiny program into &lt;code&gt;src/app/core.cljs&lt;/code&gt; file. &lt;code&gt;src&lt;/code&gt; is your project's source root directory. Also note that namespace name &lt;code&gt;app.core&lt;/code&gt; (that's how modules are called in Clojure) in the code looks exactly like &lt;code&gt;app/core.cljs&lt;/code&gt;. That's a convention in Clojure projects: namespace names should reflect directory structure starting from project's source root directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Howdy!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's compile the program into Node script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; cljs.main &lt;span class="nt"&gt;--target&lt;/span&gt; node &lt;span class="nt"&gt;--output-dir&lt;/span&gt; ./out &lt;span class="nt"&gt;--compile&lt;/span&gt; app.core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run the script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node out/main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see the output? Great, let's stop here and inspect compiler's output. Specified &lt;code&gt;out&lt;/code&gt; directory includes whole bunch of files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;out

app cljs cljs_deps.js cljsc_opts.edn goog main.js nodejs.js nodejs.js.map nodejscli.js nodejscli.js.map
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual compiled JavaScript program from your &lt;code&gt;src/app/core.cljs&lt;/code&gt; file is in &lt;code&gt;out/app/core.js&lt;/code&gt;, let's see what's inside&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;out/app/core.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Compiled by ClojureScript 1.12.42 {:target :nodejs, :nodejs-rt true, :optimizations :none}&lt;/span&gt;
&lt;span class="nx"&gt;goog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app.core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;goog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cljs.core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Howdy!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//# sourceMappingURL=core.js.map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cljs.core.println.call(null, "Howdy!");&lt;/code&gt; is your &lt;code&gt;(println "Howdy!")&lt;/code&gt;, where &lt;code&gt;println&lt;/code&gt; is actually a part of implicit &lt;code&gt;cljs.core&lt;/code&gt; namespace, which provides stdlib.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;goog.provide&lt;/code&gt; and &lt;code&gt;goog.require&lt;/code&gt; is a part of JavaScript module format of &lt;a href="https://github.com/google/closure-compiler" rel="noopener noreferrer"&gt;Google's Closure Compiler&lt;/a&gt;. Wait, what? Another compiler? Yeah, you see... ClojureScript compiler takes your source and outputs equivalent JavaScript code. Similarly to &lt;code&gt;out/app/core.js&lt;/code&gt;, there's also &lt;code&gt;out/cljs/core.js&lt;/code&gt; file which is compiled stdlib of ClojureScript. This just means that ClojureScript compiler is a source to source compiler. But how do we bundle all those JavaScript files into production ready bundle?&lt;/p&gt;

&lt;p&gt;That's the job of Closure Compiler. Closure is an optimizing JavaScript compiler that ClojureScript is using since its initial release, in &lt;a href="https://clojure.org/news/2011/07/22/introducing-clojurescript" rel="noopener noreferrer"&gt;2011&lt;/a&gt;. At the time JavaScript didn't have standard module format, remember &lt;a href="https://en.wikipedia.org/wiki/Asynchronous_module_definition" rel="noopener noreferrer"&gt;AMD&lt;/a&gt;, &lt;a href="https://github.com/umdjs/umd" rel="noopener noreferrer"&gt;UMD&lt;/a&gt;, &lt;a href="https://requirejs.org/" rel="noopener noreferrer"&gt;RequireJS&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/CommonJS" rel="noopener noreferrer"&gt;CommonJS&lt;/a&gt;? Closure folks at Google invented another one, where &lt;code&gt;goog.provide&lt;/code&gt; declares a module and &lt;code&gt;goog.require&lt;/code&gt; imports another module.&lt;/p&gt;

&lt;p&gt;ClojureScript emits Closure's module format so that the compiler can pick up and optimize generated JavaScript. Putting everything together, that's the stack you have to deal with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fromanliutikov.com%2Fblog%2Fcljs1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fromanliutikov.com%2Fblog%2Fcljs1.jpg" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To plug Closure into the equasion and produce optimized JavaScript bundle run the following command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--optimizations advanced&lt;/code&gt; option is what tells Closure to gather all generated JavaScript files into a single bundle and optimize the program by removing unused code. Closure is quite powerful compiler, you can learn more about all kinds of optimizations it performs in this &lt;a href="https://github.com/roman01la/closure-compiler-handbook" rel="noopener noreferrer"&gt;handbook&lt;/a&gt; that I created a while ago.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; cljs.main &lt;span class="nt"&gt;--target&lt;/span&gt; node &lt;span class="nt"&gt;--output-dir&lt;/span&gt; ./out &lt;span class="nt"&gt;--optimizations&lt;/span&gt; advanced &lt;span class="nt"&gt;--compile&lt;/span&gt; app.core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output &lt;code&gt;out/main.js&lt;/code&gt; file is now a self-contained JavaScript program.&lt;/p&gt;

&lt;p&gt;Let's make something cool now. Put the following code into &lt;code&gt;src/app/core.clj&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app.core&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clojure.java.shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defmacro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sh/sh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"git"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"rev-parse"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"--short"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and update your &lt;code&gt;src/app/core.cljs&lt;/code&gt; to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app.core&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require-macros&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:refer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;]]))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Howdy!"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now init a git repo in your project directory and make the first commit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add src
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"first commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile your ClojureScript project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clj &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; cljs.main &lt;span class="nt"&gt;--target&lt;/span&gt; node &lt;span class="nt"&gt;--output-dir&lt;/span&gt; ./out &lt;span class="nt"&gt;--optimizations&lt;/span&gt; advanced &lt;span class="nt"&gt;--compile&lt;/span&gt; app.core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node out/main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script should print last git commit hash. Now inspect JavaScript generated from &lt;code&gt;src/app/core.cljs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;out/app/core.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hash is embedded in the code!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Compiled by ClojureScript 1.12.42 {:static-fns true, :optimize-constants true, :target :nodejs, :nodejs-rt true, :optimizations :advanced}&lt;/span&gt;
&lt;span class="nx"&gt;goog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app.core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;goog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cljs.core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;goog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cljs.core.constants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cljs$core$IFn$_invoke$arity&lt;/span&gt;&lt;span class="nf"&gt;$variadic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;cljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prim_seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cljs$core$IFn$_invoke$arity&lt;/span&gt;&lt;span class="nf"&gt;$2&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Howdy!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;7f7e8c3&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the cool part about Lisps. You can write code in your program that runs at compile time on a program itself. It's almost like a compiler inside of a compiler, except that you don't need special plugins to traverse AST, in Clojure and Lisps in general you create macros, special functions that take code, transform it and return new code.&lt;/p&gt;

&lt;p&gt;Now, everything that you learned here is only a part of the story. We haven't touched on the language itself, how real projects are built and how ClojureScript integrates with JavaScript's ecosystem of NPM packages. ClojureScript is definitely not the easiest beast to pick up, but if you are doing front-end development and feel like digging into alternatives and learning from other languages, then there are definitely a few things you can learn from!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>clojure</category>
      <category>clojurescript</category>
    </item>
    <item>
      <title>JavaScript | Closure</title>
      <dc:creator>Jose Juarez Junior</dc:creator>
      <pubDate>Thu, 16 Oct 2025 21:56:41 +0000</pubDate>
      <link>https://dev.to/josejuarezjunior/javascript-closure-2an0</link>
      <guid>https://dev.to/josejuarezjunior/javascript-closure-2an0</guid>
      <description>&lt;p&gt;Em JavaScript, um closure (ou clausura, em português) é um conceito fundamental que acontece quando uma função “lembra” do ambiente em que foi criada, mesmo depois de esse ambiente ter sido executado.&lt;/p&gt;

&lt;p&gt;🧠 Conceito simples:&lt;/p&gt;

&lt;p&gt;Um closure é:&lt;/p&gt;

&lt;p&gt;“Uma função que tem acesso às variáveis do seu escopo léxico (ou seja, o escopo onde ela foi criada), mesmo depois que esse escopo saiu de execução.”&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 Exemplo clássico:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;criarContador&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;contador&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// variável do escopo da função criarContador&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;contador&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// função interna acessa variável externa&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contador&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;criarContador&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;contar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="nf"&gt;contar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nf"&gt;contar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O que está acontecendo aqui:
&lt;/h2&gt;

&lt;p&gt;A função criarContador é executada uma vez.&lt;br&gt;
Ela retorna uma nova função.&lt;br&gt;
Mesmo após criarContador terminar sua execução,&lt;br&gt;
a função retornada ainda tem acesso à variável contador.&lt;br&gt;
Isso é o closure: a função “lembra” do ambiente onde foi criada.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Por que isso é útil?
&lt;/h2&gt;

&lt;p&gt;Closures são usados para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulamento e privacidade de dados (como “variáveis privadas”);&lt;/li&gt;
&lt;li&gt;Funções que mantêm estado entre chamadas;&lt;/li&gt;
&lt;li&gt;Callbacks e event handlers;&lt;/li&gt;
&lt;li&gt;Factories e funções geradoras de funções.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>clojure</category>
      <category>beginners</category>
    </item>
    <item>
      <title>JavaFX In Action #21 with Vlad Protsenko, Combining Clojure with JavaFX for Game Development with Defold</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 16 Oct 2025 18:16:34 +0000</pubDate>
      <link>https://dev.to/fdelporte/javafx-in-action-21-with-vlad-protsenko-combining-clojure-with-javafx-for-game-development-with-341e</link>
      <guid>https://dev.to/fdelporte/javafx-in-action-21-with-vlad-protsenko-combining-clojure-with-javafx-for-game-development-with-341e</guid>
      <description>&lt;p&gt;Vlad Protsenko is a Clojure developer working at Defold. While I initially wanted to learn about the Cljfx project, our conversation evolved into a learning experience: a practical getting-started guide to Clojure, a hands-on demonstration of building JavaFX user interfaces with minimal code, and an inside look at the Defold game engine and its JavaFX-based IDE.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/1JL6zdkM1GU"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  About Vlad
&lt;/h2&gt;

&lt;p&gt;Vlad is a Senior Developer with proficiency in many JVM-based languages. He worked both in very small and large teams, gaining experience in developing projects of various sizes, from scratch and from legacy codebases. He enjoys full-stack development, writing backend, frontend, and Android applications. He started as a game developer and switched to developing enterprise software, currently mixing both at Defold.&lt;/p&gt;

&lt;p&gt;You can find him on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vlaaad" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/vlad-protsenko-0999b2163/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cljfx Library
&lt;/h2&gt;

&lt;p&gt;Cljfx is a declarative, functional, and extensible wrapper of JavaFX. It's inspired by the better parts of react and re-frame.&lt;/p&gt;

&lt;p&gt;Like react, it allows to specify only desired layout, and handles all actual changes underneath. Unlike react (and web in general) it does not impose xml-like structure of everything possibly having multiple children, thus it uses maps instead of hiccup for describing layout.&lt;/p&gt;

&lt;p&gt;Like reagent, it allows to specify component descriptions using simple constructs such as data and functions. Unlike reagent, it rejects using multiple stateful reactive atoms for state and instead prefers composing ui in more pure manner.&lt;/p&gt;

&lt;p&gt;Like re-frame, it provides an approach to building large applications using subscriptions and events to separate view from logic. Unlike re-frame, it has no hard-coded global state, and subscriptions work on referentially transparent values instead of ever-changing atoms.&lt;/p&gt;

&lt;p&gt;Like fn-fx, it wraps underlying JavaFX library so developer can describe everything with clojure data. Unlike fn-fx, it is more dynamic, allowing users to use maps and functions instead of macros and deftypes, and has more explicit and extensible lifecycle for components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cljfx/cljfx" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zwc63tnqjsofbczw8xf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zwc63tnqjsofbczw8xf.png" alt="Screenshot Clojure example code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Defold Game Editor IDE
&lt;/h2&gt;

&lt;p&gt;Defold is a game engine for high-performance cross-platform games. It comes fully featured out of the box. There's nothing to set up or configure, not even when building. Simply download the editor and get creative! That editor is created with JavaFX and Clojure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://defold.com/" rel="noopener noreferrer"&gt;Defold website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/defold/defold" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzivf0q8fpyy8cwjdta6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzivf0q8fpyy8cwjdta6q.png" alt="Defold IDE and example game"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Video content
&lt;/h2&gt;

&lt;p&gt;00:00 Who is Vlad?&lt;/p&gt;

&lt;p&gt;00:48 Looking back in time with ActionScript&lt;/p&gt;

&lt;p&gt;01:49 About Clojure compared to Scala and Java 21&lt;/p&gt;

&lt;p&gt;05:23 About the cljfx project&lt;/p&gt;

&lt;p&gt;06:59 Demo of Clojure code and the use of cljfx&lt;/p&gt;

&lt;p&gt;12:21 Demo of Defold game editor&lt;/p&gt;

&lt;p&gt;15:51 The goal of the cljfx project&lt;/p&gt;

&lt;p&gt;16:33 Changes needed in JavaFX&lt;/p&gt;

&lt;h2&gt;
  
  
  More JFX In Action...
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webtechie.be/tags/jfx-in-action/" rel="noopener noreferrer"&gt;Click here for more posts with JFX In Action videos&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>defold</category>
      <category>clojure</category>
    </item>
  </channel>
</rss>
