Fork me on GitHub

Oh hey, thanks for the heads up. I gave up on Calva some time ago but my colleague has been pulling some hairs with Calva+poly


No problem. Poly slowly becoming an obvious choice for many.

polylith 2

The first minute is about how to connect to a Polylith workspace in video.


I don't understand why there's a separation of bases and projects. What problem does it solve?

2️⃣ 1

The base is just the part of the project that exposes it to the outside world. A project includes potentially multiple components, and a single base. So the project is a conceptual level “up” from base.

Norman Kabir13:03:19

Why not have the base include all necessary components and leave the project to focus only on packaging into uberjar/jar? This makes for a cleaner separation: • base is responsible to ensure main works and exposes appropriate capabilities • project is responsible for externally consumable artifacts

Braden Shepherdson13:03:06

there are more important concerns to be separated. putting the implementation (say, a web server and its routing) in the base but leaving the dependencies to be specified by the project is a big part of Polylith's power.

Braden Shepherdson13:03:31

it means you can run the same server in a prod configuration with the real database/email sender/Twitter API client/etc., or in a local dev or testing way, using fake ones, just be specifying different dependencies in deps.edn.

Braden Shepherdson13:03:44

the base does, in a sense, "include all necessary components" since it :requires certain some.thing.interface namespaces. but exactly which component supplies that namespace is determined by the project.

Braden Shepherdson13:03:35

(you can do other kinds of separation too, of course. for example splitting a monolithic service into several parts. the top-level service can keep using the same sub.component.interface and never know that the implementations live on other machines now, and it has an HTTP client shim version of sub.component.interface that's calling over the network.)

Norman Kabir14:03:09

> putting the implementation (say, a web server and its routing) in the base but leaving the dependencies to be specified by the project is a big part of Polylith's power. To clarify, the base has dependencies specified for development and they are overridden by the project for production? I was under the impression that a base's main function could be executed from the REPL which implies that it has its dependencies configured. Or should there be a dev project and prod project?


Yes, the development project is always created when you create the workspace . Then you can work with all your components and bases from that “place” (the components and bases for the development project is specified in the root ./deps.edn file, which consolidates all these bricks / building blocks). All other projects have their deps.edn file under projects/ in their own directories.


Real-world report: we have a base that is used in two different projects with different sets of components. Three projects if you include development I guess.


@U04V70XH6 Can you elaborate? What's the base like, what are the components like? Or did you write about this in one of your blog posts, maybe I missed that? (Thanks for the posts, by the way, they were very informative)


On vacation right now (about to head to the airport) so I can't right now. I haven't written about this specifically (although I have written about our swappable http client components).


Okay, have a great vacation, maybe we can talk about it some other time :)

Sam Ritchie17:03:32

hey all, Q for you. I have a library, #sicmutils, which I am planning to split into many smaller component libraries. this was pretty natural with sbt in scala: and I’ve worked many years ago with lein-sub: The question is, is polylith the right fit for a library cut into pieces? I can’t tell from the docs, apologies for having to come here to ask!

Sam Ritchie18:03:26

what I want is: • the ability to declare inter-module dependencies, and have everything work well locally • when I publish, I will publish the full batch together (seems easiest) and bump everyone’s version • when the full set of jars are published, each should have proper dependencies on only the modules that they used locally, so folks can consume small libraries or the full one of they like. and, presumably, for this to work well with shadow-cljs, which currently runs my tests.


Yes, I think Polylith should be a nice fit.


You are very free to split your code up into smaller pieces, and then combine these “building blocks” into something larger (in projects) and then build artifacts from each project (e.g. jar files).

👍 1
Sam Ritchie18:03:48

Would it be possible without care to duplicate the source of those building blocks in multiple artifacts?


You will have no duplication of the source code, but each project needs a config file to specify which components (“code blocks”) to include.


If the end result is to be published in pieces, will there be a problem when the components don't declare the other components as library dependencies, when they are built and released standalone?


Or is it enough that the component deps are written as library deps in the release projects?


My guess is that the artifacts (jar files) have to look the same as today, which should be possible. When you work with the code in the development project, then you should be able to work with the source code as a single codebase (the development project). You can do a lot with, and you can get some inspiration from Polylith’s own that was written by @U04V70XH6 (thanks for that contribution!) to simplify the creation of all the jar files.


I doubt polylith will be a good fit, unless you plan to only publish a single monolithic artifact. We use polylith a little at work, and from what I can tell it is geared towards producing applications not libraries


If you try to distribute libraries with it, I believe you will end up with the jar for each library containing duplicate resources (resources with the same name, maybe not the same content) which can lead to problems when a library consumer attempts to use them down the line


Polylith seems to be a system for building uberjar type artifacts, internal dependencies are erased and just bundle into the final product, you don't want that for libraries


When I think about it, I realise that you are right @U0NCTKEV8. I think I have a solution to the problem, but that requires building a tool for it. If we could translate the workspace top namespace to unique project top namespaces when we generate the jars/libraries, then we would get the isolation we need. To do that, we need to introduce support for a “target top namespace” for each project and a tool that parses the code and changes the top namespace and all :require statements to other component interfaces in the final artefacts. Then all components would end up with different namespaces in each project/library and we will not get any version clashes between the libraries of the shared components.

👍 1

I was thinking that the release projects would not use the internal dependency references at all. IOW, while the dev project does say that a component is at {:local/root "components/util"}, the release project would state it as a maven version. But my earlier comment was thinking if this really will work, as usually the maven dependencies are declared directly in the components


We still have the problem when the libraries are used, if e.g. library a includes the component util and library b also include util then if a comes first in the classpath, the code for util will be loaded from a but if b comes first, it will use the code that lives in b.


I was thinking that in the release versions they wouldn't include them, and util would be a separate lib. But yeah, if there are components that are not meant to be released standalone, and someone would use different versions of the libs, there will be problems. Then again, that's not a problem unique to polylith, isn't it? It would happen no matter how you put your code. Only way to avoid it would be to have the util included in the build under different class path/namespace, as you were talking about, but does any tool do that?


I think that non Polylith codebases solve is by packaging shared code as libraries. Then at least the latest version of that library will be picked, and if it is backward compatible that should be fine. The problem with embedding shared code in different libraries (Polylith style) is that you sometimes will not get the latest version of that “code snippet”, and if you have e.g. added a function, then the code could potentially break.