architecture

donaldball 2017-03-13T20:20:33.714519Z

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.

seancorfield 2017-03-13T20:21:26.738319Z

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.

donaldball 2017-03-13T20:26:11.866783Z

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.

donaldball 2017-03-13T20:28:03.918458Z

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.

seancorfield 2017-03-13T20:30:49.993509Z

I think @stuartsierra advocates for protocols as a code organization tool — see his Clojure in the Large talk?

donaldball 2017-03-13T20:32:35.041377Z

I have, though it’s been a while. I think I find the argument more convincing now. 🙂

stuartsierra 2017-03-13T20:56:12.664848Z

Don't make protocols with only one implementation.

donaldball 2017-03-13T21:02:18.831017Z

Ha ha asked and answered

donaldball 2017-03-13T21:02:39.839920Z

I’m having a hard time reconciling that advice with the design experience I’ve had a few times now tho

2017-03-13T21:02:45.842645Z

there are two ways to take that

2017-03-13T21:03:20.857835Z

one way would be, if you have only one implementation, write more

donaldball 2017-03-13T21:05:06.903646Z

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

stuartsierra 2017-03-13T21:06:01.927097Z

A protocol with only one implementation is just needless indirection which increases the effort required to read and understand your code.

donaldball 2017-03-13T21:06:19.934865Z

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

stuartsierra 2017-03-13T21:07:35.965526Z

You can still treat the component as a logical unit.

donaldball 2017-03-13T21:17:11.195841Z

Possible I’m just an outlier, or maybe protocols are simply for me a useful intermediate step

donaldball 2017-03-13T21:17:12.196203Z

¯\(ツ)

donaldball 2017-03-13T21:17:14.196838Z

Thanks!

metametadata 2017-03-13T22:00:09.145581Z

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

seancorfield 2017-03-13T22:13:20.404688Z

@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?

seancorfield 2017-03-13T22:15:06.436406Z

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’.

seancorfield 2017-03-13T22:15:20.440704Z

(so that puts me somewhat in @donaldball’s camp)

stuartsierra 2017-03-13T23:50:09.873073Z

Yes, if you have mocked versions of your components, then you have more than one implementation, so the protocol serves a purpose.