This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-04-03
Channels
- # announcements (5)
- # babashka (8)
- # beginners (98)
- # biff (2)
- # calva (20)
- # cider (16)
- # clerk (2)
- # clj-kondo (20)
- # cljdoc (19)
- # clojure (90)
- # clojure-art (3)
- # clojure-boston (1)
- # clojure-europe (7)
- # clojure-nl (2)
- # clojure-norway (47)
- # clojure-uk (3)
- # clojurescript (10)
- # cursive (10)
- # data-science (1)
- # datalevin (1)
- # defnpodcast (1)
- # events (2)
- # fulcro (11)
- # gratitude (2)
- # honeysql (18)
- # hyperfiddle (11)
- # introduce-yourself (1)
- # jobs (2)
- # lambdaisland (4)
- # lsp (6)
- # malli (4)
- # membrane (3)
- # off-topic (58)
- # polylith (14)
- # portal (2)
- # releases (2)
- # ring-swagger (4)
- # tools-deps (8)
- # xtdb (8)
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?
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.
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?
The project
assembles things (usually one base
plus N components
).
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.
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
).
Does that make sense?
Yes, that makes sense.
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?
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.
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.
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).
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).
That makes more sense. Thanks for the explanation.