clojuredesign-podcast

Discussions around the Functional Design in Clojure podcast - https://clojuredesign.club/
2020-02-19T01:04:06.024200Z

Hey guys, I enjoyed the podcast this week. One question - I use (and like) the pattern of pouring my needed components (not the entire system) into my handler via a middleware for the simple reason that the ring handler by definition takes a map (the request) and returns a response. It is very easy with Integrant to integrate what is needed and keep the handler and routing logic separate from the means of adding the components. However, I totally agree with the downside that you now have “foreign keys” at the edges where you call the handler. You mentioned a pattern in which you use partial application to create a handler instead. Do you have examples of this? I’m wondering how this is done in a way that doesn’t capture system in the scope of the handler. Thanks!

rgm 2020-02-19T15:04:32.035700Z

Ah. Yeah. In practice I keep my init-key fns themselves either a partial or an anonymous fn that only plugs it together, maybe 3 lines max. The whole router form is outside the integrant goop, so it’s fairly easy to just call that function in a test to make the big handler.

rgm 2020-02-19T15:05:29.037500Z

I’ve been burned by enough frameworky frameworks that I try to keep that interface layer between my stuff and the framework extremely thin and obvious.

rgm 2020-02-19T15:08:18.039900Z

So your handler line in that threading becomes (partial big-handler-fn {:conn conn}) I think... not sure I’ve got the arg order right. Anyway, yeah, no integrant in tests.

2020-02-19T15:08:40.040100Z

So you'd create your ring-handler in a function that takes a datasource as an argument and then partial that function when you init your system (essentially split out the body of init-key into its own function)?

rgm 2020-02-19T15:11:43.041800Z

Yep. A side effect is that repl work is a lot easier too.

rgm 2020-02-19T15:13:27.044600Z

You can manually start a component in mount, integrant, component, etc. but I find it simpler to just have a thin glue between those and a regular fn, instead of having big init-key or :start or what have you forms.

rgm 2020-02-19T15:14:12.045500Z

Basically I never remember the API so I try not to have to.

2020-02-19T15:14:14.045700Z

Right, whatever solution you use should not be framework-dependent.

rgm 2020-02-19T15:18:18.046200Z

Anyway I hope I understood your q.

2020-02-19T15:18:50.046400Z

At one point I used the positional args (versus the "enhanced request") approach using compojure and I had some challenges with it, but it might work better with reitit. There were some issues with scope capture and there's also the gotcha that if you don't partially evaluate the handler you will rebuild it every time you invoke the function. This had terrible performance when we used certain middlewares (ring-webjars, for example). I like my current approach, but I think I'll revisit the other as well. It may work much better with reitit.

2020-02-19T15:19:16.046600Z

Yeah, I just wanted to see an example of what the authors were thinking to make sure I wasn't missing anything.

rgm 2020-02-19T15:23:16.047300Z

Well, I’m also hoping this is actually an example of that.

rgm 2020-02-19T15:25:44.049900Z

Could be with reitit. I never got that good with compojure and hadn’t really internalized when things were happening given the macros, which made it tough for me to understand its interplay with component.

2020-02-19T15:26:42.050100Z

I believe it is. If the global handler is going to be generated via a function that takes in its stateful items I think it has to wrap the entire global handler unless you wrap your endpoints individually, but then you'd have a spaghetti code nightmare.

rgm 2020-02-19T15:31:33.053400Z

So far I’m liking how the one global handler switchyard that partially hydrates simpler things into a full routing tree is working in practice. Add middlewares and it can turn into a lot of goop, but at least it’s in one place and usually fits on two halves of one screen.

rgm 2020-02-19T17:18:57.053600Z

(I've updated the gist to incorporate this discussion about disentangling from whichever injection framework is in play).

nate 2020-02-19T01:14:48.025700Z

Hey Mark. I'll see if I can extract a minimal example. I can't promise that it will be soon, I'll ping you.

2020-02-19T01:27:12.026Z

Thanks! No worries on the timeline.

mmeix 2020-02-19T14:07:56.027300Z

Which in itself would be a subject: how to sensibly arrange your function args (just hinting … )

rgm 2020-02-19T14:50:11.030800Z

I think that was one of my big FP moments, eventually understanding what someone meant when they said underscore.js and lodash got argument order wrong everywhere. It’s eg. _.map(coll, f) and so partial is ugly and involves placeholders.