I'm new to Polylith and I think I understand the overall goals and pattern, but I've run into something that I'm not 100% sure about. So let's say I have three components - config, logger, and database. Both the logger and database use the config component, and the database also uses the logger component. Am I breaking the pattern here or is this okay?
No circular references, right? Why do you think this breaks any patterns?
There are no explicit dependencies in components, only in projects
No circular references or anything. I was just looking at and thinking this seemed off, but I've read through your example and the RealWorld one and it seemed fine.
So, any component can depend on any other component?
As long as there are no circular references
We have ~170 components and some of those low-level ones are used (transitively) by "everything".
Okay, that makes sense.
I'm still feeling my way around this structure, but I do like how it forces you to think about component interfaces.
Yup. You think about naming, and you think about dependencies, because everything is done through interfaces.
I'm also learning about component systems, ie. the stuartsierra/component library. I'm still a little fuzzy on that. But if I understand it correctly, they are for stateful components like database connections. Is that right?
Yes, mostly
https://clojurians.slack.com/archives/C015AL9QYH1/p1737028240185019
Quick Q! Is there a way to fetch dependant bricks for a brick programmatically from Clojure for custom tooling. For example
(poly/deps :brick/foo)I'm working on a Polylith project that has a lot of components and project.
I'm looking into creating a component to collect functionalities for a feature.
I'd like to programmatically traverse all the dependant projects/components where this feature is used to build documentation and release notes for this particular feature, since it's dispersed across all the projects.
Therefore I'm looking into if Polylith has baked in functionality to collect this information for me from the whole project.
I see that the Poly CLI lists the dependants by running deps brick:.... -> Can I use this somehow from Clojure code.
I'm also interested on other suggestions on how to go about documentation.
Thanks!
Well, you can use Polylith as a library but there's nothing in the CLI API specifically for what you need so you'd have to dig around in the source a bit... Who is the consumer of this documentation and info? For our public API, we've documented the REST-ish API separately, and our build process generates HTML from Markdown and adds it to the uberjar for our API service so it's available through the same URL as the API itself. If we were starting over, we'd probably use Swagger and provide a more automated/standard documentation approach.
Thanks, I'll keep digging. I'm hacking the first pass of this PoC by parsing the EDN files. I'll take another look at the CLJ API if we decide to take this further. The consumers are technical people who are not familiar with this side of the project. I want to create docs that gives a high overview of how this feature is spread over different projects and components. So when new developers take a look they can get the big picture with a quick look instead of tracing manually where the code is used etc.
@vaisanen.toni howdy! How about creating a separate project with manually picking the bricks you need for this + using https://github.com/dundalek/dinodoc/ with this classpath? Too much of a handwork?
I need to look into this, thanks Mark!
Can you explain your use case? I suspect you can just use the Clojure CLI but if need to understand better what actual problem you're trying to solve.
BTW, @vaisanen.toni. Dinodoc supports compiling docs for a whole Polylith workspace OOTB. Just in case if this feature simplifies your task.
Is it a ok for a component to depend on other component(s)? e.g. have a direct dependency in deps.edn like:
poly/metrics {:local/root "../metrics"}Thanks a lot for this explanation this was not completely clear to me either
@ikitommi hey Tommi! This is the trick that differs a Poly workspace from a regular multi-module Clojure Deps project. The approach/tool introduce this idea of separating the static/codebase architecture from the deployment-time architecture. So your classpath only gets combined into a whole in a particular project.
Components do not have dependencies on components, only on libraries. Only the project specifies the concrete dependencies.
A component's code may reference other components' interface namespaces, but the deps.edn does not include any dependencies.
thanks, and that’s how I read this, but… how would you do the following with polylith:
1. a mini-framework, component Ato define how to create and run tasks - protocols needed to implement, helpers etc
2. component B a that uses the A defining concrete tasks for certain subdomain.
a. no dependencies to A? so won’t compile on itself as it would like to point to namespaces in A 🤔
3. component C that is like B but for a different domain / purpose
4. base D that uses A to run tasks for B and C
5. project E to bundle everything together
a. depends on all of A, B, C and D
Am I using components or even whole polylith in a wrong way in that example?
or should A be outside of polylith as a non-polylith thing, just code in a local root in the same repo, e.g. used in B and C with:
library/a {:local/root "../../libraries/a"}The deps.edn file in components (and in bases) should never contain dependencies for other components -- even if the source code in that brick references other components via interface nses. Only projects deps.edn files contain those local dependencies -- and that includes the :dev alias which is the "development" project.
If you have a component A that has one or more interface nses, those can be referenced by any other bricks' code.
In your example, none of A, B, C, or D would list other bricks in deps.edn; only project E (and development) would list local dependencies.
For point 2a, you would not "compile on itself". You only compile/build/test via projects (including development).
B, C, D source code would all refer to interface nses in A, B, and C as needed.
Does that answer your question(s)?
yes, thanks. It answers. Only projects are concrete, everything else is just abstract building blocks. 🙇
I've been using the latest SHA of the cljs-support PR to test the updates as they're made... however, when changes are force-pushed to a branch, that kills the SHA I was using and I have to keep updating my deps.edn. This is a) really annoying and b) bad practice anyway, as far as I'm concerned: force pushing should almost never be necessary if you're using git correctly.
Maybe @tengstrand can speak to why he keeps force-pushes changes? @furkan3ayraktar You've also done this on that branch.
The alternative is that I just ignore work-in-progress pull requests and only test changes after you've merged them and then open new issues for bugs you've introduced. Would you prefer that?
Using force-pushing is totally fine while you work in an isolated, non-public branch. In OSS community this isn’t usually the case after the first “feedback welcome” proposal.
@mstoyukhin I think you mean "while" not "until" there, right?
You are right, we need to stop force pushing, so you can continue using your sha. I forgot that it could make life hard for other people. I rebased and force pushed, to keep the commits clean, but I don't need to do that any more. Good that you pointed this out.
I have had to learn to use git merge while working in a branch and avoiding conflicts on the PR for the aforementioned reason of breaking SHA's
Sure, sure. I’m not a native speaker, mille pardons.