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.

Reply via email to