+1. I also challenge the starting condition that most code will be data access - that was my assumption (when I migrated from Spring/Hibernate). It doesn't take much rigour to ensure every side effecting fn is _only_ concerned with the side effect leaving lots of non-side-effecting code.
Also, do remember that clojure.jdbc works on plain Clojure maps so you get half-way there simply by returning the rows to persist. My advice would be to do the 'Clojure' thing and isolate every side-effecting code (idiomatically post-fixed with the '!') and see how it goes. Although Mikera might have unintentionally put you off it, I would highly recommend Prismatic Schema from day one :-). Mikera writes: > On Monday, 1 February 2016 05:19:17 UTC+8, John Krasnay wrote: >> >> Hi all, >> >> I'm migrating an application from Java/Spring to Clojure and I'm searching >> for a good, functional approach. The app exposes a REST interface using >> compojure-api and primarily interacts with a relational database and sends >> email. >> >> I think most people end up passing their database connection (and other >> stateful resources as required) around to non-pure functions that do the >> side-effectful work, while trying to push as much business logic into pure >> functions possible. My problem with this approach is that most of my app's >> functionality is in database interactions, so most of my functionality ends >> up being non-pure and difficult to test. For example, to unit test my >> functions it seems I'd have to mock my database connection. >> >> Instead of this, I'm considering an approach where my functions instead >> return a data structure containing a description of the side-effects to be >> performed (e.g. "insert these rows into this table", "send this email", >> ...), and having a single non-pure function that does all the >> side-effectful work described by the structure. >> >> From what I've read, it seems is sort of how Haskell does IO in a pure >> functional manner, using their IO monad. >> >> Has anyone tried this sort of approach? Are there any libraries that might >> help? Any pitfalls I might be setting myself up for? >> > > I'm sure that you could get this approach to work, but it sets off some > alarm bells in my head. > > Problems you may face: > > a) You are effectively developing a programming language, where your > state-affecting code is represented in data. Clojure already does that.... > why reinvent the wheel? I'm reminded of Grrenspun's tenth rule of > programming: "Any sufficiently complicated C or Fortran program contains an > ad hoc, informally-specified, bug-ridden, slow implementation of half of > Common Lisp." > > b) Representing operations in code seems neat, but it gets tricky when you > have dependencies between them. What if one operation requires conditional > execution that depends on the result of a previous operation? You'll need > branching and control flow to handle this in a general way, which is > non-trivial. What if one set of side effects writes to places that are > subsequently "read" by later operations? You'll need to mock or model a > database engine if you want to test / simulate this directly. > > c) Clojure is an dynamically typed language (sadly, one of it's few > flaws....) . The lack of compiler support for type verification makes it > harder to keep track of exactly the type of data passing through your > deeply composed functions and data structures. Trying to represent graphs > of operations as data as well is only likely to make things worse. Yes > there are tools such as Schema, but they have their own cost in terms of > runtime performance (if you use them for validation) and runtime > complexity. It's possible to get right, but I would predict quite a lot of > pain along the way. > > I'd strongly suggest trying this the more conventional Clojure way first > (e.g. using Stuart Sierra's component approach). This can get pretty close > to being a nice functional style, and is very easy to test (you just need > to mock one or two components and you are usually good). You may ultimately > find some areas why you want to implement a DSL, but trying to write the > whole application in this fashion from the beginning seems to me like a bit > of a high risk strategy. -- 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.