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 > <javascript:>> 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 > > 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 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.