Fork me on GitHub

Hit a major milestone today: finally refactored one of our big "legacy" apps into two bases and a few components:

projects: 17   interfaces: 28
  bases:    5    components: 28
We now have 23,138 lines of source refactored to Polylith (up from ~7,000 last week) and 2,063 lines of tests (yeah, this legacy app is mostly tested manually by QA). This shook out some "interesting" bugs around how our test fixtures were working, as well as uncovering a couple of bugs in our build script that we had "gotten away with" until this refactoring.

metal 6
polylith 6

@seancorfield: It would be awesome, if you're able / willing to share, to hear about general improvements to dev experience / speed / simplicity of after migration vs before.


I'm blogging about our migration at


But we already had a fairly good setup with our monorepo: a single REPL for all code that could run for weeks without reloads.


that's really the primary productivitiser™


we've 5 repos right now and it's like nails on a -ing chalkboard whenever we have to work across a repo boundary


A;cid=C013B7MQHJQ made me wonder: If bricks shouldn't have deps on each other but, say the user brick uses the interface from the foo brick in its source code, then not all of the namespaces from user will be loadable using only user/deps.edn so I'm assuming tests for bricks aren't executed from there. What is the purpose of the :test alias of user/deps.edn then?


The built in test runner that is executed when you run the test command looks into all bricks and finds their test code and calculates all dependencies (libraries and paths) needed to run the tests for each project. This is described in the section, under “How tests are executed”.


Thanks. And if the foo interface has multiple implementations in the workspace, how will one be chosen?


I couldn't find that in the section you mentioned


In Polylith, context is defined by projects. In other words, the tests run in a projects context. So let’s say you have project1 that includes foo1 and bar components. You have another project, project2 with foo2, bar and baz components. Let’s say foo1 and foo2 implements the same foo interface. Then, Polylith will run the tests in project1 context with foo1 and bar. Also it will run the tests in project2 context with foo2 bar and baz. We achieve this with using different classloaders so the tests run in the correct context. You can check out how the test-runner is implemented


Even brick tests run in a project's context?


Thank you, that's very interesting indeed!


It’s like Lego™ bricks, they have input and output points but without connected, they are not meaningful alone. However, you can connect them in different ways as long as connection points match.


Sure, although a brick will probably have some unit tests that aren't dependent on the outside context - I take it those are executed in all contexts the brick is included in?


Yes, but that is also configurable, so that you can choose which bricks to test for a specific project. I recommend you to read the section of the documentation, and if something is still unclear, I’m happy to answer your questions!


Thank you again.

👍 2

a project i did a while ago is pseudo-polylith! the files here are a base, each folder is a component, and the repo is a project!


Interesting! It feels “on the road” to a Polylith-style codebase, and it’s quite easy to imagine how that source directory structure would map into an equivalent set of Components.


and i kinda covered my thinking about this set up here, although not nearly as lucidly as the fine polylith authors have 😅

polylith 4
🙏 2

Fulcro RAD has the same kind of domain-based source code organisation. And is the preferred/ideal/encouraged setup for all Fulcro projects.

👍 4

> This shook out some "interesting" bugs around how our test fixtures were working, as well as uncovering a couple of bugs in our build script that we had "gotten away with" until this refactoring. So it turns out the build script "bug" is actually a deeper bug in depstar -- don't worry: it works fine for the usage where you cd projects/foo && clojure -X:uberjar which I'm sure is how most sane Polylith folks actually use it. Of course, insane me insisted on writing my build.clj script to iterate over projects and use a little-known part of tools.deps.alpha to calculate a basis in the context of an assumed directory... which exposed that depstar doesn't respect that same context in a few places!

👍 2
😲 6