clojure 2026-06-09

Has anyone experimented with one function per namespace only? I have read this article https://chrisfrew.in/blog/advanced-design-patterns-the-case-for-one-function-per-file/ I tried it with a clojure game project and it actually makes total sense Namespaces are noun.verb/f Dependencies are organically per function Each require form only pulls in code it depends on and nothing else 🤯

I haven't tried this, but I think his argument makes more sense in js where people don't prefix libraries, with (require '[util.math :as math]) it's always clear from the usage math/add math/subtract etc.

☝️ 2

An argument more suitable for Clojure may be storing functions in a database and doing away with files altogether + automatic namespace relocation facilities for any var

☝️ 2

Mimicking fronted way of development on backend is a horrible thing

☝️ 2
🙃 1

This hardly is frontend related no? It's something like the "one class per file" thing introduced around Java

I wonder (not from a place of knowledge fwiw) if perhaps this makes more sense with AI agents, where this could possibly be more efficient re: context window usage?

It's just a bad practice.

➕ 1

Such a complex topic. For me, code organisation is about how it should fit in my head. The best case is when it all fits in one screen, but that is unsustainable in the long run. But that means that as projects grow, I tend to put stuff in namespaces based on coherence. When I don’t need the details I can just assume some-ns to do its job. When it doesn’t, I can jump into some-ns and have a full overview of these related functions to wrap my head around.

@igrishaev can you elaborate why do you think it is bad practice?

In general, it's a poor pattern: in a language X, do like they do in a language Y. If you use X, do like people do in X. For experiment, try to implement the clojure.core namespace by putting each function into a separate file.

🙏 1
😅 1

@ben.sless this is on my todo list! I've experimented with it in janet with sqlite to get something closer to image based development.

Given that a function is going to be named as a verb or a noun (in general), it seems like you'd end up with noun.verb/verb or noun.verb/noun which don't make sense to me. Specifically, based on the article, you'd have math.add/add and math.subtract/subtract etc, and the (JS) article uses the equivalent of (:require [math.add :refer [add]] [math.subtract :refer [subtract]]) -- which I would definitely consider non-idiomatic in Clojure.

☝️ 1
⭐ 1

Example from my code The biggest advantage is each namespace pulls only exactly dependencies And namespace dependency tree is function dependency tree In my opinion this solves code organisation naturally

(ns clojure.math.vector2.angle-deg
  (:require [clojure.math :as math]
            [clojure.math.vector2.dot :as dot]
            [clojure.math.vector2.crs :as crs]))

(defn f
  "Returns the angle in degrees of this vector relative to the given reference vector.
  Angles are towards the positive y-axis (counter-clockwise) in the `[0, 360-` range."
  [this reference]
  (let [angle (math/to-degrees
               (math/atan2 (crs/f reference this)
                           (dot/f reference this)))]
    (if (neg? angle)
      (+ angle 360)
      angle)))

So, every function in every ns is just called f?

Sometimes I have used :refer also but then you repeat the name so now I just use 'f' ... Yes

The naming can be alias as needed right in the ns macro. So far have not tried to rename one var only

I think this is absolutely most amazing insight...

(ns clojure.math.vector2.crs)

(defn f
  "Calculates the 2D cross product between this and the given vector"
  [[this-x this-y] [x y]]
  (- (* this-x y)
     (* this-y x)))

I'm not convinced it would scale -- our code at work:

Clojure source 633 files 123534 total loc,
    5226 fns, 1258 of which are private,
We'd need nearly 10x the number of namespaces, which I would expect to impact memory usage -- and local dev tool usage for anything that scans source files.

That's a good point. But is all the code in one project? It's probably different libraries right ?

Another advantage - no private functions!

I'm leaning the other way stick it all in a single file like in elisp. 🤣

💯 2
🤓 1
☝️ 3

@mx2000 It's a monorepo, producing about two dozen artifacts (uberjars) for deployment.

In terms of file organization this was a real game changer for us: https://www.jimmybogard.com/vertical-slice-architecture/

cool idea

i remember light table was trying to move toward treating functions as the primary unit of organization rather than files

i wonder if this one-function-per-file pattern would've made it more possible to build a "drafting table" editor like light table

Hi everyone, A community member recently opened the following issue in the Clojure code smells catalog, and I'd be interested in hearing the community's thoughts on it: https://github.com/nufuturo-ufcg/clj-smells-catalog/issues/47 The discussion is around reader literals and EDN tags. If you have experience with these topics, I'd appreciate any perspectives, agreements, disagreements, or examples from real-world projects. Thanks!

Is there some way to wrap the reading from a lazy data structure so that when it becomes empty a specified action is taken? Close the stream, in this case?

(let [coll (take 1000 (range))
      reporting-coll (->> coll
                          (sequence
                            (fn [rf]
                              (completing rf
                                          (fn [result]
                                            (println "DONE")
                                            result)))))]
  (dorun reporting-coll))

This is almost always not what you want (as a quick and dirty hack, it's fine). My general advice is: If you care about when things happen, don't use lazy sequences.

➕ 6
☝️ 2