Does anyone else sometimes write protocols even when there is only one implementation? I sometimes find value in using the abstractions to write the calling code at a higher-level, without some of the incidental complexity obscuring the intent. But I’ve heard the critique a few times that protocols should have at least 2 impls to justify their weight.
I have done that in a few cases — like you, where I felt the clarity of the protocol helped understanding of the code — but I would consider it a rare edge case rather than best practice.
The case I’m contemplating now is one where I had a mess of side-effecty code that was doing something like 4 different business jobs and I could not find a satisfying organization… until I went for a walk, realized I could express these as 4 different protocols, and it decomposed nicely.
I have had similar experiences when working with larger clojure codebases. At a certain point, the organizational benefit of protocols to clarify responsibilities carries some real weight, at least to me.
I think @stuartsierra advocates for protocols as a code organization tool — see his Clojure in the Large talk?
I have, though it’s been a while. I think I find the argument more convincing now. 🙂
Don't make protocols with only one implementation.
Ha ha asked and answered
I’m having a hard time reconciling that advice with the design experience I’ve had a few times now tho
there are two ways to take that
one way would be, if you have only one implementation, write more
I think my pushback would be: 1. while it would now be fairly easy to remove the protocols and just keep the organization confined by namespace, I (apparently!) could not have gotten there without the design aid of the protocols
A protocol with only one implementation is just needless indirection which increases the effort required to read and understand your code.
and 2. the readability of the highest-level of code is, to me at least, significantly aided by having components named by role interacting, instead of the incidental clutter of values that would otherwise have been closed over by the impl
You can still treat the component as a logical unit.
Possible I’m just an outlier, or maybe protocols are simply for me a useful intermediate step
¯\(ツ)/¯
Thanks!
I often use protocols even with single implementations because protocol instances are easy to stub/mock in unit tests with smt. like clj-fakes
:
https://metametadata.github.io/clj-fakes/user-guide/#protocol-fakes
@stuartsierra In your Clojure in the Large talk you advocated protocols, as I recall, but I think that was in conjunction with an assumption that you would also be defining mock components? Am I remembering incorrectly?
I used protocols in the design of one of my libraries, as it helped clarify the API design — but I refactored the protocols away after using it for a while and establishing where there were likely to be multiple implementations (kept protocols) and where there weren’t (removed protocols). I did find protocols helpful to articulate my design tho’.
(so that puts me somewhat in @donaldball’s camp)
Yes, if you have mocked versions of your components, then you have more than one implementation, so the protocol serves a purpose.