polylith

https://polylith.gitbook.io/ and https://github.com/polyfy/polylith
seancorfield 2021-03-27T01:14:37.048500Z

I made it to my first runnable JAR file! Still reading the (long) README...

šŸ‘ 2
tengstrand 2021-03-27T04:04:40.070600Z

I have an idea about the interface naming convention @seancorfield. In workspace.edn we currently support setting the name of the interface with the :interface-ns attribute, where ā€œinterfaceā€ is the default value. My idea is to support another option where the interface name always has the same name as the the interface, by e.g. setting interface-nsto :interface-name so if the name of the interface is database then it will expect to find a database.clj namespace at the top level (which would be the interface of that component). Then you are free to put the implementing namespaces wherever you want, e.g. at the top level and/or in sub namespaces. We could also support setting interface-ns to :component-name so that if you have two components that implements the invoice interface, e.g. invoiceand invoice-remote , their respective namespaces would be`invoice.clj` and invoice_remote.clj . Iā€™m not sure whatā€™s best here, and if we should support only one behaviour (then all Polylith codebases would act the same which has its benefits) or if people would prefer to choose one of the three different options (or maybe restrict it to two). We havenā€™t discussed this within the Polylith team yet, but I like the idea so far.

seancorfield 2021-03-27T04:09:54.071Z

I think that's a good "alternate behavior".

seancorfield 2021-03-27T04:10:30.071600Z

I think it addresses the random/arbitrary naming concern and it makes the code easier to navigate in an editor.

seancorfield 2021-03-27T04:24:28.074700Z

I'm thinking about the :interface-name vs :component-name... I don't feel I've had enough experience with Polylith to comment, but given you can create component name:... interface:... I'm not sure how :component-name would work?

seancorfield 2021-03-27T04:26:25.075400Z

:interface-name feels like what I would want based on my (small) experience today -- and given how we already organize our monorepo.

seancorfield 2021-03-27T04:27:24.077400Z

(BTW, the biggest difference between our monorepo and Polylith is that we don't distinguish between bases, components, and projects -- those all exist as subprojects at the top-level under their unique names)

tengstrand 2021-03-27T04:27:32.077600Z

I have the same feeling, that :interface-name + ā€œinterfaceā€ would be enough.

tengstrand 2021-03-27T04:27:49.077800Z

Ok.

tengstrand 2021-03-27T04:28:46.078600Z

Yes, you get the sharing with the monorepo, but to replace things (and the encapsulation) you need the interfaces.

seancorfield 2021-03-27T04:29:47.079900Z

Yeah, that replacement isn't a pressure we've found (in a decade of work with, now, 112K lines of code).

seancorfield 2021-03-27T04:31:03.081800Z

We don't really draw a distinction between what Polylith calls bases and projects either, to be honest. Ours have always had a 1:1 relationship. So far šŸ™‚ But it's an interesting distinction to consider.

tengstrand 2021-03-27T04:35:22.085700Z

So basically, to get Lego-like bricks, you need all of them: monorepo, project, base, component, interface. Maybe you will found pieces of code in your 40 bases that could be extracted into components and shared across these 40 projects or that you will divide these bases into components instead of only using namespaces within bases. Time will tell! šŸ™‚

tengstrand 2021-03-27T04:39:04.086800Z

The Polylith codebase has 25 components, 3 bases, shared across five projects/artifacts + the development project:

tengstrand 2021-03-27T04:41:14.089100Z

For example the file component is responsible for accessing the file system and is used by all projects. This is quite common, that you have common functionality across projects/artefacts that can be put into a component and shared across projects.

seancorfield 2021-03-27T04:43:14.090Z

We only have about 14 "bases" in your terms but, yes, the other 27 "components" include several that are bigger than Lego šŸ™‚

šŸ‘ 1
tengstrand 2021-03-27T04:47:09.092800Z

It would be interesting to see your project, so if yo want, you could execute this and mail me: poly ws out:dot-clojure.ednbecause then I can type poly info ws-file:dot-clojure.edn and get an idea!

tengstrand 2021-03-27T04:47:58.093600Z

(or if you have pushed into a branch already)

seancorfield 2021-03-27T04:48:01.093700Z

We've also made a pragmatic choice to only build one artifact that contains several -main functions that provide a slew of cron jobs. Deploying a separate JAR for each process would add more complication than benefits. I suspect you might consider each of those jobs to be a separate project?

seancorfield 2021-03-27T04:49:47.094900Z

Not sure what you're referring to with that dot-clojure reference?

seancorfield 2021-03-27T04:50:21.095500Z

And poly wouldn't run in our work project because it's not a "poly workspace"

tengstrand 2021-03-27T04:52:30.096900Z

Ok, thought you converted the dot-clojure project into a Polylith workspace, but maybe you worked on another project when testing Polylith.

seancorfield 2021-03-27T04:53:19.098200Z

https://github.com/seancorfield/dot-clojure <-- this is what I'm referring to by dot-clojure; it's my user-level deps.edn file (and a support script dev.clj).

seancorfield 2021-03-27T04:53:28.098700Z

It's not a "project" with code.

tengstrand 2021-03-27T04:53:30.098900Z

The api artifact can answer the question what projects that have changed since the last successful build. Then itā€™s up to the build script to handle all projects i one build or to have separate build projects.

seancorfield 2021-03-27T04:53:50.099300Z

It's just developer conveniences for work with every project.

tengstrand 2021-03-27T04:55:00.099800Z

Okay, now I see!

seancorfield 2021-03-27T04:56:02.100500Z

It's where folks who use the CLI a lot would typically put all of their developer tooling that isn't specific to a project.

tengstrand 2021-03-27T04:57:02.100800Z

Ok, I get it.

seancorfield 2021-03-27T04:57:34.101400Z

Practicalli has one too https://github.com/practicalli/clojure-deps-edn (much better documented and intended more for beginners to learn the CLI with).

šŸ‘ 1
seancorfield 2021-03-27T18:03:29.103300Z

If a Polylith project is going to be entirely in-house and never publish libraries, it would seem that the :top-namespace isnā€™t really needed. Can it be nil so users can use whatever full namespace names they want?

seancorfield 2021-03-27T18:05:29.105600Z

I ask because I realized that at work we have older namespaces as worldsingles.* and some newer ones as ws.* ā€” most of our newer apps are ws.&lt;project&gt; for the top-level entry point ā€” but we also have some &lt;project&gt;.* ones. Yes, I know, potential conflicts yadda yadda yadda, but Iā€™m just wondering about how much flexibility Polylith could allow in that areaā€¦

2021-03-27T19:40:47.105700Z

As a bystander in this discussion I love the way Sean is pushing polylith to be less strict without losing the important parts.

seancorfield 2021-03-27T19:46:35.107500Z

Thanks. Iā€™m trying to find what aspects of Polylith add value over the monorepo/deps setup with already have. And I have to say that the command-line tool that track dependencies and git status and what needs testing is very interesting (we have some of that in an assortment of scripts but itā€™s pretty ad hoc).

seancorfield 2021-03-27T19:47:35.108500Z

Iā€™m an old skeptic so I need to be convinced something ā€œrestrictiveā€ really does improve things šŸ™‚

2021-03-27T20:03:58.108900Z

Yeah, I worked in a monorepo and we also had lots of adhoc scripts to only test necessary code but I would like to have a standard for that. I think the problem is other people restrictions, we are usually fine with the ones we come with. šŸ˜‰

seancorfield 2021-03-27T20:37:27.115900Z

We have a general shell script (called build) that does some of what poly does including ā€œrun all tests that affect this ā€˜projectā€™ā€ and ā€œrun tests for all subprojects affected by this changed subprojectā€ ā€” but our subprojects are pretty coarse-grained and our deployment artifacts (uberjars) and ā€œbigā€ ā€” in my mind, at least: a couple of them are 70MB but the smallest are under 30MB and Iā€™d like to tease apart our codebase to produce smaller artifacts, perhaps even if it means more artifacts. But converting it to a Polylith structure would be a massive undertaking at this point. If I can break up things into more ā€œcomponent-sizedā€ pieces, that will be a win.

tengstrand 2021-03-27T20:38:08.116100Z

I actually implemented support for having arbitrary top namespace per brick (component and base) earlier, in a separate bransch. We decided to not merge that code because it made the Polylith code more complex but maybe more importantly, it complicated the use of Polylith and as you said @seancorfield it also opened up for naming clashes. But yes, it is possible.

seancorfield 2021-03-27T20:45:29.122200Z

It wouldnā€™t be a bad thing for us to adopt at least a standard short ns prefix at work butā€¦ this is a codebase that goes back over ten years and we were new to Clojure back thenā€¦ ĀÆ\(惄)/ĀÆ

tengstrand 2021-03-27T20:46:18.122800Z

You can put the code for each ā€œproject/artefactā€ that you have today @seancorfield into a base + make sure that all of them use the same top namespace, e.g. com.company and then each base would live in e.g. com.company.mybase. You would have to refactor the namespaces for each base to conform to that pattern. Then you could create a project for each base and include only that base in each of them. That should be doable.

seancorfield 2021-03-27T20:47:54.124400Z

I was thinking more: * Anything that starts with ws leave alone * Anything else rename to add ws. prefix * Over time, rename ws.worldsingles.* to something more appropriate as I move code around šŸ™‚

tengstrand 2021-03-27T20:49:21.126Z

You donā€™t need to convert the whole codebase, you could start with one base and then migrate one ā€œprojectā€ at a time.

seancorfield 2021-03-27T20:49:52.126500Z

But, as Iā€™ve noted before, we have what you would call ā€œbasesā€, that have namespaces like ws.billing so our repo structure tends to be like wsbilling/src/ws/billing.clj and the immediate implementation is ws.billing.stuff šŸ™‚

tengstrand 2021-03-27T20:52:34.127600Z

We decided to also support your suggested naming convention of the interfaces, by the way!

seancorfield 2021-03-27T20:54:51.131600Z

Oh, cool! I think Polylith will be more approachable for folks if it looks a bit less like a set of ā€œweirdā€ naming conventions and directory structure and more like a ā€œreasonableā€ convention/structure whose goal is to make tooling easier to write/use ā€” and then it wonā€™t distract from the architecture portion which is the Lego-like aspect of it.

tengstrand 2021-03-27T21:02:14.136300Z

I donā€™t really agree that the four top directories components, bases, development, and projectsare weird. Itā€™s kind of the opposite. It really helps you understand and reason about the codebase, not the least if you are new to a codebase. I know that you like your setup that you are used to, but having a directory called componentswith letā€™s say 50 directories with descriptive names and one entry point (the interface) is actually super helpful. @furkan3ayraktar has worked with several Polylith projects (around five) and the benefit you get by this structure has a lot of value.

seancorfield 2021-03-27T21:31:33.137200Z

I know you donā€™t think they are weird, but this is part of why several folks react to Polylith as ā€œa naming conventionā€ or a ā€œdirectory structureā€ šŸ™‚

seancorfield 2021-03-27T21:33:03.138400Z

I will say that we find having the top-level directories in a monorepo being related to the business or functionality is ā€œnaturalā€ for us (and it seems to be the more common monorepo structure).

seancorfield 2021-03-27T21:52:04.144200Z

@tengstrand Can you remind me what the thinking was behind have projects having deps.edn vs being aliases in the root deps.edn? I think you explained but canā€™t find it in the chat history so I donā€™t know where we discussed it.

tengstrand 2021-03-27T22:03:43.153200Z

There are a reason why we use interfaces, and that is the same reason interfaces are used in OO, to decouple parts of our system and to be able swap what concrete implementations to use without affecting the consumer of that interface. That is an example of why we use different concepts like interfaces. They are there to give you more value and in the end to help people to work efficiently with the code and to be able to easily arrange how to execute the code in production. As I have said before, itā€™s like Clojure, itā€™s hard to convince people that are used to work in a different way (like OO) but when you have used it for a while, you start to appreciate the fast feedback loop and the Lego-like feeling it gives you.

seancorfield 2021-03-27T22:05:30.153600Z

@tengstrand Just checking: Did you miss this Q? Can you remind me what the thinking was behind projects having deps.edn vs being aliases in the root deps.edn? I think you explained but canā€™t find it in the chat history so I donā€™t know where we discussed it.

tengstrand 2021-03-28T10:29:22.174200Z

@seancorfield @pavlos Each project may have its own tests and resources associated with it. So instead of adding everything as aliases at the root deps.edn, we put everything for each project in its own place. For example, if you have ten projects where each has several aliases, src, tests, resources, and dependencies specified, the root deps.edn file would get huge. If we choose to have everything in the root deps.edn, to be able to distinguish between development related aliases and project specific aliases, we would also need to prefix the latter, which would result in extra complexity. To let each project live in a separate folder also allow us to easily recognise changes that effects only a specific project, which is used by the poly tool to support incremental testing. This is a design choice we have made, because we believe this is simpler and follows the single responsibility principle.

tengstrand 2021-03-29T04:21:15.216500Z

You are right about that when we build an artifact from a project, we only include the source code from the bricks. Itā€™s also true that you have the opportunity to put some shared library dependencies at the project level (e.g. Clojure itself, or logging). There is one case when we sometimes need to add code to a project, and that is when we add tests that is specific to that project. In that case we will add a test directory to the project containing these tests. There is a case when you will ā€œbake inā€ extra files/resources to the final deployable artifact, and that is if you have the need to have project specific resources. In that case you will also add resources at the project level.

1
seancorfield 2021-03-29T04:22:31.216800Z

See the main thread for my progress with a clj-new template for polylith -- and problems running project tests.

tengstrand 2021-03-29T04:23:06.217Z

Yes, looking at it now.

seancorfield 2021-03-27T22:06:21.154200Z

I think it was to do with some restriction in t.d.a / deps.edn but I canā€™t remember the detailsā€¦

tengstrand 2021-03-27T22:11:28.158500Z

At least the last time we checked, the IDE we used didnā€™t pick up the test directories for the bricks when we used the`:local/root`syntax, which affected the development experience negatively. For the other projects, we use our own test runner to solve that problem, which means that we can include the bricks as dependencies.

tengstrand 2021-03-27T22:17:08.161Z

The reason we put the paths in the`:dev` alias as extra-paths in ./deps.edn is that we wanted to isolate the dependencies we use for development into one place.

seancorfield 2021-03-27T22:17:30.161500Z

That doesnā€™t sound like an answer to my question. Iā€™m not sure how weā€™re miscommunicating here.

tengstrand 2021-03-27T22:18:30.162700Z

Okay, now I understand your questionā€¦

seancorfield 2021-03-27T22:19:06.164100Z

Iā€™ll try from another side: in Polylith, it seems that you have to cd projects/myapp and then run clojure there to do the compile/packagingā€¦ we do it via aliases in the root deps.edn file so we donā€™t have to cd, we can build directly from the root folder.

seancorfield 2021-03-27T22:19:57.165200Z

Perhaps partly because we use depstar and it handles the classes folder and does AOT etc all in one place?

seancorfield 2021-03-27T22:20:24.166Z

(it actually uses a temp directory for classes so it doesnā€™t clutter up your workspace)

tengstrand 2021-03-27T22:23:25.167900Z

A project can contain many bricks and also aliases. If you have many projects, we liked the idea to let each project have their own deps.edn file instead of putting everything into one huge deps.edn file. But maybe you just mean the ā€œbuildingā€ aliases?

tengstrand 2021-03-27T22:27:17.170200Z

So far, we donā€™t require people to install any extra tooling like depstar or similar to be able to work with the code and to build it (the poly tool only makes it more convenient, but itā€™s not required).

seancorfield 2021-03-27T22:28:10.171100Z

Weā€™re still not communicating.

tengstrand 2021-03-27T22:28:32.171600Z

Maybe a video meeting some day could be an alternative?

seancorfield 2021-03-27T22:29:00.172300Z

Iā€™ll go back search the chat history in various places and see if I can find the comments you made about projects that Iā€™m referring to.

tengstrand 2021-03-27T22:29:16.172500Z

Ok

pavlosmelissinos 2021-03-27T22:57:07.173Z

The way I see it, polylith projects are independent entities with public apis, so it makes sense for their dependencies to also be decoupled from the root deps.edn.

pavlosmelissinos 2021-03-27T23:00:44.173200Z

As in, let's say you're developing an rss client. You could have 4 polylith projects: rss feed api, cli, desktop, web

pavlosmelissinos 2021-03-27T23:02:46.173300Z

From the perspective of the user, would it be better to have a single deps.edn for all of them or keep them separate? Edit: by "user" I meant anyone who might want to use your code. That could include future you, or the maintainer of another repo.

pavlosmelissinos 2021-03-27T23:04:45.173400Z

Not sure if it helps at all in the discussion (feel free to ignore it if not) but that's my $0.02 :man-shrugging:

šŸ‘ 1