This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-11-08
Channels
- # babashka (18)
- # beginners (35)
- # biff (15)
- # cider (24)
- # clj-commons (26)
- # clj-kondo (12)
- # clojure (18)
- # clojure-austin (1)
- # clojure-dev (2)
- # clojure-europe (15)
- # clojure-losangeles (1)
- # clojure-nl (1)
- # clojure-norway (88)
- # clojure-seattle (2)
- # clojure-spec (14)
- # clojure-uk (27)
- # clojuredesign-podcast (5)
- # clojurescript (25)
- # cursive (3)
- # datahike (26)
- # datalevin (13)
- # datomic (39)
- # etaoin (19)
- # events (1)
- # fulcro (12)
- # graphql (1)
- # hyperfiddle (40)
- # introduce-yourself (3)
- # joyride (8)
- # lsp (53)
- # missionary (7)
- # nyc (1)
- # off-topic (31)
- # overtone (10)
- # reitit (6)
- # shadow-cljs (9)
- # slack-help (9)
- # thejaloniki (1)
- # tools-deps (12)
I think I'm starting to feel the pain of type systems and the thing to which Rich Hickey referred to in «Spec-ulation» and (partly) in «Maybe Not». Type systems require either a new type for any form that might have a date, so with a Maybe<Date> field, or they require for me to change an existing type and put some default value in all the places where it's used but doesn't really matter. Or maybe it's just me, maybe I just built a bad complex program.
Maybe I'll be able to migrate to Clojure while it's not too late for such migrations, but that won't be helpful to people in my organization, since, if Rust is hard for them, I suspect Clojure will be much harder, so they probably won't be too active in maintaining this project. Oh well.
There is, also, another factor. With rust, in the «rocket» framework, there are «request guards». They ensure your request «gets some data», but can also be used for authentication. They are structs that implement from_request.
With Clojure, to achieve the same kind of behavior, I would need some kind of admin-only-middlewar, but, since reitit has handlers in one place and the router in another place, I'm actually afraid of how it's decoupled. What if someone forgets to add the admin-only-middleware (or any other middleware for that matter), and my function isn't guaranteed to get what it expects. Also, spec is confusing.
However, I just though how rust implements it, it generates code. I guess I'll write a defhandler
macro that will add keys into a map, and ensure some crucial ones are in the map. Yeah, that's it.
sketching so I don't forget
(defhandler name (request)
{:post {:key1 ::spec-thing
:admin-only field-extracting-fn}}
,,,)
or maybe there's ideas better than that? IdkIn reitit, you can apply middleware to route chunks and every sub route will inherit it, as i remember it
In your rust code, that’s the perfect place for “…Default::default()”. Not quite as smooth, but makes such handling nicer.
Yeah, but maps feel nicer the more variations of kv pairs come in a request. At the same time, I love the strictness, the guarantees of Rust.
it’s a me problem
Haha yeah i have the exact same issue with Rust. I love the strictness until I want a bag of options and then I’m tearing my hair out
creating a struct of optionals
Maybe I’ll create a must-have
middleware
> What if someone forgets to add the admin-only-middleware What if I forget to wash my hands when I come back from outside? This can also be forgotten in Rust.
@U028ART884X, yes but in Rocket the required params are coupled with the handler function. Very tightly.
> but in Rocket the required params are coupled with the handler function. Very tightly What if somebody uses wrong function? And maybe requires access that seems ok for the time being but doesn't actually work later down the line? Open this video at 3:20: https://youtube.com/watch?v=aSEQfqNYNAc "But we're programmers, we need protection!" - Rich Hickey
They can’t use the wrong function, since the function is also coupled with routing logic :)
You can't prevent people from making mistakes. It doesn't mean that you should use more blunt knife (Clojure has no protection but then what if somebody creates a Rust route function that requests route parameters and falsely claims it works properly?). You still have no protection from human stupidity.
You write a handler, with one rocket annotation, and everything’s ensured via codegen. Clojure doesn’t like coupled things though, it likes composable stuff. That’s the source of my worries. As I said, it’s a me issue, my own paranoia
> You write a handler, with one rocket annotation, and everything’s ensured via codegen You write a handler and you need to use this handler to build another handler. Now what? Then you write another annotation that does basically the same thing. Now you have two things that are almost the same but slightly different. Somebody uses one or the other down the line but then you want to do something else with your second annotation. Then you decide to refactor it because type system has you covered but you didn't write the integration test because: 1. this annotation is hard to bootstrap -- you need to spin up a framework for it 2. type system has you covered anyway -- why even write even a single test because if it compiles it works, right? 3. I have only one annotation, why would I want a test -- I can test by hand So you don't write that test and then you have two annotations... five annotations... then you get a bug where you don't remember what the annotation has to do. And then you wish you had the integration test. But now it's too hairy. And Clojure? "Things are not coupled and I should write the integration test right away because stuff might change beyond recognition"
You should check out Rocket before speaking. I don’t need integration tests for functions that don’t do any business logic, and are just CMS glue code
If function doesn't do business logic it should be removed as the code doesn't get run. If it's part of the framework then it participates in auth or other logic which is also business logic.
Am I gonna test how a tested library fetches values out of the database? Or am I gonna test how the tested template library renders the well defined contents?
> Am I gonna test how a tested library fetches values out of the database? Or am I gonna test how the tested template library renders the well defined contents? I'm not sure why you have this thread. You already answered the question of what you want to do. I'm not sure if you consider a choice at this point.
My whole app is just “check user auth -> upload their file -> return response on success”
This is an off topic rant, I’ll figure it out
I was trying to add counterpoints to your arguments of which slippery slope you could take. Clojure will have some rough points and you know it in advance, but types will also have their hiccups which you don't think about in advance -- the main one being false sense of security that you told about when you said "no, it's code but I don't need to test it as it's coupled". And in the end of the day you choose what is comfort to you.
I know the hiccups of types, that’s why I started the thread. I’m considering clojure
I just want my authentication guards to be in the same area of code as the function, not in the routing file somewhere. I’ll just make a middleware and use it together with the functions
Or you could create an intergration test which would do a for
loop to execute each route in your config and check for 403 :thinking_face:
And then I'll have 3 places to update whenever I add an endpoint that requires authentication. I can do a single test for my authentication wrapper, but then that'd need an initialized database with valid credentials that I'll need to test against