On 31 July 2015 at 09:54, J. Pablo Fernández <pup...@pupeno.com> wrote: > > For me, the thing is, I have a traditional relational database here, this > is already far from pure. For example, calling (db/create-user " > pup...@pupeno.com") twice will not only not return the same thing the > second time, it'll actually raise an exception the second time. Also, the > database connection is *global state* unless each function creates its own > connection, which would be terrible. So, this global state also breaks > functional purity. > > The problem with the second aspect of breaking purity as far as I can see > is this: at some point, this global state has to be picked up and used, so > at some point a function will *not* get a database connection passed to it > but *will* access the database by using this global connection. >
Why does the database connection have to be global state? Why not pass it through your functions as an argument? So in your example scenario, you might write something like: (defn create-user [db user] (sql/insert! db "users" user)) (defn create [db user] (create-user db (update user :password encrypt-password))) (defn register [db user] (create db user) (send-welcome-email user)) (defn make-handler [{:keys [db]}] (routes (POST "/users" [& user] (register db (select-keys user [:email :password]))))) This style ensures that the functions only have access to the database you want them to have access to, and also allows you to deal with multiple databases simultaneously. For example, often I'll have a dev database and a test database, and ideally I want to be able to run my tests in my REPL (or via Cider) without clearing the data in my dev database. Another advantage of this approach is in test performance. Frequently I'll place my lowest database functions in a protocol: (defprotocol UserDatabase (create-user [db user])) This allows me to implement a mock database for performing fast integration tests. While most databases are stateful, so we obviously sacrifice purity, that doesn't mean we shouldn't continue limiting the use of other dangerous tools like dynamic or global vars. Clojure is a pragmatic language, but this means that it just trusts us to be disciplined. - James -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.