Fork me on GitHub
#clojuredesign-podcast
<
2024-02-28
>
genekim22:02:58

@neumann It was so great to talk with you today — and it’s been way too long since our last hangout at Conj/2019! And thank you for your advice of discouraging use of defprotocol — I didn’t realize the extent to which it was so disruptive to workflow, because of the way it depends on actual Java classes. It was funny to see your mongodb wrapper, which looked exactly like my namespace I did for another project — one big flat namespace with all the queries I ever needed in it. I am going to replace my crazy experiment of nested OO-approach I had taken for xtdb using defprotocol and defrecord. (Although, it was inspired by how often you mentioned those in your podcast. Or was it multimethods?) But here’s a question: in your mongodb code, you don’t catch exceptions in your code. Why? (In my code, I catch exceptions, because otherwise, I’d forgot to.) Thanks in advance! PS: for those of you who might not know, @neumann is available for consulting opportunities, if you’re looking for someone with his expertise to help on your projects! 🎉🎉🎉

❤️ 1
neumann22:02:04

@U6VPZS1EK It was great talking with you too! Thanks for reaching out! I had a blast! I think there is definitely a place for defprotocol, but that place is a lot smaller than my OO-ingrained instincts want me to believe! I think the key is to use it when you want interchangable things. The application is going to use each thing in the same (or similar) manner, but the way each thing goes about it may be different. Think ISeq in Clojure which is available on maps, lists, vectors, etc. For a protocol, smaller and more single-purpose focused is usually better too. Like you mentioned, I just have a plain-old-namespace per MongoDB collection. I have a function for each query I want. Eg, suppose a user namespace: user/for-id, user/for-email, user/all, user/update-email, etc. Each of those functions takes db as the first argument, and whatever parameters are needed for the query. The principle here is: flat is simple. Hierarchy and abstraction create more things to figure out and decide. Why not catch exceptions? The functions have no idea what the overall process is. They simply exist to consolidate all interaction with the database and give names to different queries. Some other code that is trying to get something done is going to use that function, and the call site should be in charge of handing the failure appropriately based on it's goals.

genekim23:02:56

Wonderful, @neumann! (Half joking: I blame you and @U0510902N for filling my head with dangerous ideas about trying defprotocol in the first place. 😆 ) For context for the rest of you: inspired by how many times I heard Christoph and Nate mention defprotocol, defrecord, multimethods, I finally tried it…. It initially seemed like a good idea to have: • xtdb.record: here I made a defprotocol, where I defined operations like “get-all!,” “get-by-id,” “get-by-xtid,” “upsert-by-xtid”, etc… • and then in xtdb.photo xtdb.podcast xtdb.photo-summary, I made a defrecord that fulfilled that interface. Over the last couple of months, I started having problems with pointers to the old Java classes, and never figuring out the workflow to get rid of them, refresh them, etc. And it seemed like a hassle at time, sometimes a huge hassle, because of old Java object issue. Christoph then showed me his namespace full of mongodb operations — which reminded me of some of my own code that looked just like this! And it was in comparison so much easier to use. (Despite being 2000 lines of code, it was never difficult to find the query function.) So, I’m super excited to jettison all of my defprotocol/defrecord in favor of this much simpler model — which I expect I’ll be as delighted about as the refactoring of the LLM wrapper above! Thanks again, @neumann!

❤️ 2
🎉 2
slipset20:03:06

On protocols, and polymorphism in general, I believe @U07S8JGF7 wrote on Twitter once that we use open dispatch way to much in our apps - where closed dispatch suffices. Open dispatch is much more useful in libraries and frameworks where you want to offer the possibility for the client to extend your stuff.

awyeah 1