Curious how folks who use Cognitect's aws-api handle testing. We are currently using with-redefs
on invoke
while testing. This feels gross. I'm considering creating a protocol that has an invoke
method. We'd then extend the Client type to use this protocol and use our own invoke
method instead of the invoke function in aws-api. This would let us create mock clients during tests, removing the need for with-redefs.
(aws/invoke (aws/client {:api :dynamodb :http-client MY_MOCK_HTTP_CLIENT}) {:op :ListTables})
Something like that ^ ?IMHO you should abstract in front of aws-api and let it be an impl detail
I suppose. I'd prefer to work at the aws-api client level than the request level.
don't try to intercept individual ops, but make pluggable application level things
Have you applied something similar to Datomic?
no, mostly because the API to datomic is already pretty generic data
small example of pluggable impls ^
Hmm. That's an interesting pattern. Essentially all effects become protocols?
i'm not making prescriptions about all
but i do think that coupling to aws-api, or clj-http, or any X library, is a bad idea
program to abstractions, not concretions
It is something similar to what Rich Hickey said a lot of times. Clojure is an improvement on the classic Perlis quote "It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures."
Clojure improves this by providing 100 fns on no data structure. The fns instead depend on abstractions like clojure.lang.IPersistentMap
, clojure.lang.ISeq
etc.
https://en.wikipedia.org/wiki/Dependency_inversion_principle (program to abstractions, not concretions). You can apply this principle to "abstraction" in this conversation, i.e. Clojure Protocols or Java Interfaces are implementation details of the abstract concept of "abstraction" 🙂
@dchelimsky Are there any other resources on that pattern that you know of that apply to functional programming and/or Clojure?
Looking for things that help me think about what the abstractions are. A good point in the wiki is: > Implementing generic interfaces everywhere in a project makes it harder to understand and maintain. At each step the reader will ask themself what are the other implementations of this interface and the response is generally: only mocks.
I feel it's a bad abstraction if it's not self-explanatory and requires readers to ponder the possible implementations to understand the abstraction. Where and how to abstract is a very hard problem indeed. Zach Tellman gave an excellent talk on the topic: https://www.youtube.com/watch?v=x9pxbnFC4aQ Rich Hickey's talks have also help me a lot in thinking about these things. These in particular: Simple Made Easy: https://www.youtube.com/watch?v=kGlVcSMgtV4 Design, Composition, and Performance: https://www.youtube.com/watch?v=MCZ3YgeEUPg
actually I will make a prescription @kenny :
grep for with-redefs
in your projects and parameterize those things you find
I could swear I've head this elsewhere 🙂 I quite like this train of thought. Is this from a talk or blog or simply a product of your own creation?
Sounds like something Rich Hickey would say