Let's compare for example
(defn lookup-users-i []
(query (get-db-conn)
'[:find [?user ...] :in $ :where [?user :user/name _]]))
to
(defn lookup-users-ii [db-conn]
(query db-conn
'[:find [?user ...] :in $ :where [?user :user/name _]]))
The first version is easier to invoke via the REPL because you offload any db connection setup logic to the get-db-conn function. You don't need to worry about building a connection and passing it in. On the flip-side, at the lookup-user-i call-sites you don't have arguments going in, which provides folks reading the code with less context regarding the function's behavior.
My current pattern is a map of override functions. I can give them defaults using :or, and overwrite side effecting functions, or define a function in my scope. This works for me so far, and enables tests easily (since part of a side effecting function is the contract by which you call the side effects) and allows you to call a different function for repl side work.
One could make two different arities of the function:
This way, one gets the best of both worlds, at the cost of a little extra typing upfront.
My current pattern is a map of override functions. I can give them defaults using
:or
, and overwrite side effecting functions, or define a function in my scope. This works for me so far, and enables tests easily (since part of a side effecting function is the contract by which you call the side effects) and allows you to call a different function for repl side work.