Everything you say is true. And programming is always about picking the right trade-offs at the right time, making this sort of conversation one that can never come to a *right* answer.
But… in this case Pablo was experiencing concrete problems: those problems stemmed from how easy it was to make mistakes having both a global connection pool and the option to pass around specific connections which had transactions open. Having two conflicting ways of doing the same thing was causing problems. Eliminating at least one of them is a solution. Pablo felt that he might want to eliminate both and add a new mechanism. A number of people (including me) felt that Pablo’s proposed solution would, potentially, lead to new problems and that eliminating only one of the original mechanisms would be sufficient to solve his problems. In a very real sense, the pragmatic solution and the most “pure” solution seem - to me at least - to be the same. R. > On 3 Aug 2015, at 18:19, Dmitri <dmitri.sotni...@gmail.com> wrote: > > While I generally agree that purity is something to strive for, I think it's > also important to consider the problem that's being solved in each particular > scenario. While creating stateless database query functions and passing the > connection round explicitly achieves purity, it's not entirely clear what > practical problem that's addressing. However, the practical disadvantages are > that you end up with is additional variable being passed around and more > opportunities for user error as is the case with transactions. While there is > mental overhead in having to understand that the functions use an implicit > connection, there's conversely additional mental overhead in having to > remember what connection to use when with the explicit approach. > > In some applications it might be valuable to pass the database around > explicitly. Yet, many of the applications in the wild tend to deal with a > single database instance where a connection is created when the application > is started and retained for the lifecycle of the application. Creating the > additional hoops for the user to jump through for purely theoretical benefit > seems unwarranted in this scenario. > > > On Monday, August 3, 2015 at 6:48:05 PM UTC-4, Rob Lally wrote: > Hey Pablo, > > Sorry, you are completely correct: I accidentally typed transaction when I > meant connection. My bad. > > I don’t understand what you mean by connections having to be global when > dealing with an RDBMS. It is true that you normally want to pool them to > conserve resources, and that pooling may be global in nature - but it also > may not be. Quality of Service demands often necessitate multiple pools to > the same data-source to be created and accessed independently. You also, > sometimes, want to access different databases from the same application, that > gets much harder - and your code becomes less general if you need to > reference specific global connection-pools. > > I’m also a little confused by your suggestion that it would be impossible to > enclose each test in a transaction. The article you point to shows one way. > Another way I’ve used often is to declare a var holding a ref and in a > fixture initialise/close a connection around the test. The test function then > derefences the var holding the connection passing it into the function under > test. This does make it impossible to run tests in parallel, but that’s not > something I’ve ever tried. Creating tests that access shared resources is a > little bit uglier than in a OO language where you could more easily reference > an instance variable but it isn’t much worse, and a little macro-pixie dust > can make it all go away. > > I will say that it has been my experience that you don’t find yourself > passing database connection pools around everywhere. As your code grows you > naturally extract components/protocols that wrap all that up. Your > ring-handler doesn’t need a connection it needs some sort of data-access > component. That component needs a connection/connection pool but that can be > passed in at construction time. I have feared the creation of functions that > need an ever increasing number of parameters that need to be passed on, but > it isn’t something I find happens in practice. Of course, YMMV. > > I would respectfully suggest that the solutions are not the same. My way has > no global state and functional purity-lite (those connections are rarely > idempotent): which are obviously only theoretical benefits. But it does work > when I do it; I like my code, I don’t have problems working with it, and I > genuinely don’t face any of the challenges you’re struggling with. > > > > R. > > > >> On 3 Aug 2015, at 03:19, J. Pablo Fernández <pup...@ <>pupeno.com >> <http://pupeno.com/>> wrote: >> >> Rob, >> >> The transactions are not global, the transactions are local. Connections are >> global and there's no way around it with the constraints of a traditional >> RDBMs. Your idea of making the global connection unavailable for code that's >> in the context of a transaction would prevent the errors I'm trying to >> prevent but you would still required to pass the connection around, which in >> a webapp, means that the whole chain of function calls, pretty much >> everything, would have a database connection. That is ugly in some cases, >> impossible in others. >> >> A piece of code that would be impossible is to enclose each test in a >> transaction using clojure.test: >> http://stackoverflow.com/questions/31735423/how-to-pass-a-value-from-a-fixture-to-a-test-with-clojure-test >> >> <http://stackoverflow.com/questions/31735423/how-to-pass-a-value-from-a-fixture-to-a-test-with-clojure-test> >> >> Furthermore, I don't think this solution gains you any purity, you still >> have a global estate and you are hiding it away when starting a transaction. >> My proposal was to make it work instead of hiding it. They are rather >> equivalent from the complexity point of view. > > > -- > 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 > <mailto: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 > <mailto:clojure+unsubscr...@googlegroups.com> > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > <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 > <mailto:clojure+unsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout > <https://groups.google.com/d/optout>. -- 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.