Fork me on GitHub
#architecture
<
2022-02-19
>
Casey18:02:58

While thinking and researching the topic of appropriate abstraction layers in clojure I came across this juxt article https://www.juxt.pro/blog/abstract-clojure I'm interested in the hexagonal architecture and want to play with the idea, perhaps refactoring a large codebase to use some of the ideas. We're struggling with the fact that our codebase isn't testable without a full runtime infra stack (DB, external queues, elastic search, redis etc). This causes tests to be slow and difficult to wire up. The root cause is that the system has side effecting functions at the top and bottom (a sort of traditional layered architecture). Simply speaking, routes get an integrant system map and this is plumbed all the way to the bottom, with different levels peeling the IO bit they need out of the system map. We have several pure cores but these are isolated and glued together with impure orchestrating-type systems. We can't test the system (or a group of subsystems) as a whole. The article proposes two solutions: protocols or partially applied functions. Using protocols to specify interfaces in a Repository pattern seems rather Java-ish and not like idiomatic clojure (though I don't think we're experts on what is idiomatic clojure). Passing partially applied functions around seems like it could get unwieldy as the number of functions grows. Both suffer from the, not insignificant flaw imo, that you can't jump from a function call site to implementation with your editor. What are the community's thoughts on this?

vemv20:02:36

there will be always at least a couple schools of thought among clojurists when it comes to abstraction. I've participated in multiple teams where protocols were chosen and they did exactly what we foresaw - testable, explicit code. Do they resemble of Java codebases? I guess so, but one would only fool himself to think that 100.00% of OOP/java practices are bad. As far as tooling is concerned, I think clojure-lsp added protocol support recently (if it wasn't there already). It's not out of the question for CIDER either.

mynomoto15:02:18

One article good that describes the problem and one solution tradeoffs is https://www.jamesshore.com/v2/blog/2018/testing-without-mocks the author has a video serie in which he live codes that solution. He uses oo but it also works using a more functional style.

Ivan22:02:40

Have a look also at this talk about the hexagonal architecture https://youtu.be/0EX3UIl-Sd8

msolli10:02:51

> Using protocols to specify interfaces in a Repository pattern seems rather Java-ish and not like idiomatic clojure Protocols are fundamental in Clojure, and are fully idiomatic. They provide several advantages over Java interfaces and are a fine mechanism for introducing abstractions to Clojure code. I maintain a large codebase where we use the Repository pattern with protocols more or less like in the Juxt article. I highly recommend trying this route for cleaning up your code. > Simply speaking, routes get an integrant system map and this is plumbed all the way to the bottom, with different levels peeling the IO bit they need out of the system map. Try making a repository protocol with some related DB functions (for example) and add this (or rather, an implementation of this protocol) to the Integrant system. Then refactor the domain code to use this abstractions instead of the concrete bits.

Casey16:02:13

@U06BEJGKD Assuming you use SQL, are your transactions inside the Repository boundary?

msolli20:02:10

No, I have a with-transactionfunction (and an accompanying macro for sugar) that wraps code that should happen in a transaction. Multiple Repository functions may be called inside the transaction, even from different Repositories (in violation of DDD orthodoxy, no doubt, but useful when there is low write contention).

Drew Verlee20:02:53

I tend to think the specifics dominate when it comes to improvement. What's a part of your system that keeps surprising you how it behaves? Here is a Reddit post generated some discussion a while back on that article. https://www.reddit.com/r/Clojure/comments/r1x1ji/juxt_blog_abstract_clojure/

👍 1