Fork me on GitHub
#polylith
<
2024-04-03
>
mafcocinco01:04:28

Is there typically a 1:1 relationship between projects and bases? What as an example of when you might assemble more then one base into a single project artifact?

seancorfield01:04:53

I wouldn't expect more than one base in a single project -- since a base is an entry point, it typically has a -main, and you're usually building an uberjar to invoke via java -jar so it has a default (single) entry point. That said, you could bundle multiple bases into a single project and then pick the ns to run -main from at application startup time (we have one base that has half a dozen namespaces with with -main functions -- but only one project for that since we just use that one base). You could also have multiple projects using the same base but with different libraries or different implementations of a single component. For example, we have an HTTP client component with two implementations: one uses hato (and therefore JDK 11's built-in client), the other uses clj-http so it can be run on JDK 8, and we have a single application that has to run on JDK 8 but otherwise shares code with the (now) JDK 21 applications. We actually have a separate base for that as well -- although it's really a "library" that our legacy application uses. You could also have bases without a project. We have an artifact-uploader-cli base that has no corresponding project because it's only ever used via an alias in our (top-level) deps.edn file.

mafcocinco01:04:53

So, with that, a base assembles components into something that is usable by the outside world (i.e. has HTTP end-points, CLI, etc.). The point of a project is really for build configuration and artifact generation. Fair to say?

seancorfield01:04:27

The project assembles things (usually one base plus N components).

seancorfield02:04:27

A base provides an entry point -- and may use a bunch of components -- but which implementations it gets is all decided by what's in the project deps.edn file.

seancorfield02:04:28

Neither bases nor components specify any components in their deps.edn file. Only projects (and the "development" project -- the :dev alias in the top-level deps.edn file) specify components as dependencies (and usually one base).

seancorfield02:04:34

Does that make sense?

mafcocinco03:04:13

Yes, that makes sense.

mafcocinco03:04:03

An example might be helpful: One thing that (I thought) I would make into a component is configuration. aero recommends using wrapper functions to access the underlying configuration, which seems like a good idea and this seems like a good fit for being a component. However, it would also seem that other components (or at least bases) would need to access the configuration component to pull configuration information that they need (`port` for example on an http server). But based on what you said above, this would not be the case? Are there no dependencies across components where component A would want to make use of component B's interface functions?

seancorfield04:04:36

I think you've misunderstood how Polylith works in that area? The code will use namespaces from "elsewhere" (e.g., other components) but the components deps.edn files do not specify those dependencies. Only the projects deps.edn files specify which specific base(s) and components are assembled.

seancorfield04:04:04

At work, we have a configuration component (that wraps aero in fact) and it is "used" in a huge number of other components and bases. But none of those have a deps.edn dependency on it. All of the projects that include a base or component that needs the configuration component will specify the implementation to use.

seancorfield04:04:55

Most components only have one implementation but at work we have a few with two implementations -- same interface -- and the projects determine which implementation is used (at build time, essentially).

seancorfield04:04:10

The poly tool will check that a project satisfies all of the necessary dependencies (by recursively checking that a matching implementation component is present for every interface used by the projects dependencies).

mafcocinco04:04:26

That makes more sense. Thanks for the explanation.