hi all, just want to clarify, is it a bug or intended behaviour, when I have multiple components shares the same interface, if I have not interface namespaces with different path poly marks component doesn't share the same interface between components, but declares it's own even if there is no such an interface, let me explain in dir structure, probably it would be easier to explain
components/kafka-event-broker
├── src
│ └── myproj
│ └── kafka_event_broker
│ ├── core.clj
│ └── event_broker
│ └── interface.clj ;; interface requires myproj.kafka_event_broker.core
in such situation poly shows me, that component implements kafka_event_broker interface, when I expect event_broker. I'd like to have such a dir structure so I may work on internal namespace loading them manually without clashes with all components shares one interface.Yes, it's really about tradeoffs. The more I work with Polylith, the better I understand how to structure my code, instead of just transforming one ball of mud into another. (:
You need to change the package structure to something like this:
components/kafka-event-broker
├── src
│ └── myproj
│ └── event_broker
│ ├── interface.clj
│ ├── core.clj
Now the interface name of the kafka-event-broker component will be event-broker .yep, thank you for answering, I already fixed that in this way, I'm only thinking, why we have this limitation, this seems pretty natural to me to have an independent implementation under it's own namespaces, and only interface shares the exact one the same. Anyway, im just exploring polymorphism in Polylith at the moment, and I've seen so far it's great for some things, but during development, it could be hard to work on multiple component with the same interface, since you need a separate REPLs for each combination, you are working on. My point is if we could keep component internals (not the interface itself) goes under unique namespaces, it could make it easier to work with them in the same REPL, since such namespaces could be loaded all at the same time. But maybe im missing something.
While the interface ns must match, the impl ns can differ across those components. You could have:
• myproj.event-broker.interface require myproj.event-broker.kafka in the kafka-event-broker component, and
• myproj.event-broker.interface require myproj.event-broker.other in the other-event-broker component
That means you can load both implementations into the REPL at the same time and experiment with them. You can only load one interface tho'.
yep, but if both of my broker components contains myproj.event-broker.other ns that could be a problem and I have no choice, but to carefully keep all name different across all the implementations, while if I could use myproj.other-event-broker.core (unique "path"), while interface is still myproj.event-broker.interface instead it could help avoid this without any loses, as it seems to me so far.
As for now I could achieve something like that using components with unique interfaces for all the implementations and proxy them by "interface" components, but it sounds like an overhead, and I rather stick to just what we have now.
This is not really critical for me since I could remove one ns and load another after all, but initially the fact that poly resolves component interface not on the actual xxx.interface ns, but on any other namespaces, that component may contains just confused me. Actually, I could see this may lead to problem with clashes in nss between components, that doesn't share one interface and could be used simultaneously, for example if there are user, and post components, and both of them have the same myproj.something-common.core namespace, but in situation like that it's better to explicitly prohibit this declaring namespaces with "paths" different that the interface and emit an error on check or more intelligently check if there is no such clashes over the projects.
Yes, Polylith's approach is more restrictive -- and that prevents potential ambiguities -- and the tradeoff is that working in a single REPL with, essentially, multiple profiles (selecting different implementations of shared interfaces) is a little harder and takes a bit more work. Given that these alternate implementations are a "project build-time choice" rather than a runtime choice, this is a fairly reasonable limitation, IMO. You can always start your (development) REPL with a specific profile if you want to work primarily with that profile's set of implementations.
yes, I'm just exploring Polylith, and this approach is something uncommon yet interesting for me) Actually, at least with Cider its not a problem to have multiple REPLs and switching between them, that's how I'm doing it now. Anyway, thank you for the answer and for you work on Polylith itself (:
FWIW, when I first looked at Polylith, I was very skeptical and very public about that. It was only once I'd forced myself to use it for a while that I began to see the various proscriptions and restrictions as valuable... We migrated our (large) legacy codebase to Polylith and now have about 150k lines of Clojure organized into nearly 170 components and 24 bases and that just keeps growing. We have a few shared interfaces with alternate implementations in all that -- but not as many as we used to have, as we've refactored and streamlined code.