https://github.com/idanmel/tic-tac-clojure/ After a couple of years of trying to stick with learning Clojure, I created a tic-tac-toe "game engine". Any feedback would be appreciated. π
Thanks everyone, I'll make the recommended changes.
@jaihindhreddy @pavlos Coming from Python, it will not common practice to use private functions. Is it common practice to use defn- in Clojure?
@idanmel In my experience, what's more common, is for projects to have entire namespaces with impl in their name, and no promises made to the consumer. This way might be a little cleaner. But you do tend to see defn- too. Also, there is no enforcement as such. You can still call private fns from other namespaces (, you'll get warnings of course).
@jaihindhreddy "namespaces withΒ `impl`Β in their name" Not sure what that means, and google comes up short for me. Where can I read about it?
@idanmel For an example of this, https://github.com/tonsky/datascript/tree/master/src/datascript. The impl folder contains namespaces that are to be considered implementation detail by consumers.
You can also put :private true https://clojure.org/reference/metadata on namespaces too (like defn- does to functions), but I don't think that does anything.
Thanks @jaihindhreddy, I'll look into it!
Also even though this is a pretty contained project and you don't have a lot to gain, on top of replacing most defns with defn- (or instead of it) you can have a separate api namespace just for symbols that are meant to be exposed to the world
I'd also add some specs and try to use them to validate the user's input (e.g. move)
to find out if/how I could "reduce" the boilerplate in the turn function
Instead of This is the only function that should be used from outside this namespace..., you can use defn- to make fns private to the namespace.
One thing I noticed is that your docstrings should be before the function parameters. Anything after the function parameters is evaluated, so each function is actually initializing the string the immediately forgetting about it
in draw-status you can use when instead of if
A style I prefer is to destructure right in the parameters.. i.e. instead of
(defn f [foo]
(let [{:keys [a b]} foo] ...))
you could just do:
(defn f [{:keys [a b]}] ...)