polylith

https://polylith.gitbook.io/ and https://github.com/polyfy/polylith
tengstrand 2021-06-10T03:34:27.090100Z

If all IDE’s had support for defining the bricks using :local/root then this would be less of a problem, because then the development environment would look very similar to the other projects, except that it also needs to define the test paths (and profiles, if any).

tengstrand 2021-06-10T04:24:16.097600Z

About your question @seancorfield “I haven’t figured out a good way, yet, of setting up test-only resources that can still easily be overridden when running the `poly` tool -- especially since the way you do it for the alias and for the AOT/shell-script version are essentially different. Hard problems.“. One solution would be to add support for profiles for all kind of projects, not just development. Then all projects could have a default profile that would be used if no profile was specified, and one or more profiles that can switch in/out different combinations of dependencies and paths (for example an extra test resources directory). So if we run the test command without any profiles specified, it would use the default profile for each project (if exists) or if we run e.g. poly test +myprofile then it will use the +myprofile alias in each project (if any) when running the tests.

seancorfield 2021-06-10T19:27:05.113400Z

I can no longer figure out what problem I was trying to solve at the time I wrote the above so I’m not sure whether or not profiles would address the issue. For now, things are working “as expected” so I’m all good. I think this was mostly around — quite literally — a resources folder that should be part of the :dev context but didn’t seem to be picked up when running test :dev, but I solved it by specifying an absolute path in my environment variable. If I ever run into a similar issue (or somehow manage to repro what I had tripped over) I’ll let you know!

1👍
seancorfield 2021-06-10T04:27:08.097700Z

Oh, interesting... Sounds like Leiningen 🙂 When I read over the profiles stuff in the docs, it didn't make much sense but I'll go back and take another look.

seancorfield 2021-06-10T04:32:01.098Z

Ah, I see what you mean: right now this is development only. I'll have to go back and look at what I was trying to do -- since it wasn't related to projects -- this was about components that are not yet used by a project (only by our existing "legacy" subprojects).

1👍
seancorfield 2021-06-10T04:43:50.098300Z

Yeah, reading over that, it might well do what I need... I'll let you know after I try it out tomorrow at work...

1👍
tengstrand 2021-06-10T05:36:16.098600Z

I have pushed some changes to the issue-66 branch: - Create ~/.polylith/config.edn file if not exists when executing the poly command. - Pass in JVM_OPTS in the poly command script. - Resolve library versions correctly if used in more than one brick. - Added :auto-add to the :vcs key, e.g. {:name “git”, :auto-add false}, that will only add files and directories to git when executing the create command if set to true.  - Only retrieve the latest sha if :latest-sha is passed in + make sure that it works offline.  - Updated the help.

seancorfield 2021-06-10T05:41:16.098800Z

Nice! I’ve wanted :auto-add false for a while 🙂

1😃
seancorfield 2021-06-10T06:42:09.100200Z

An interactive poly shell 🙂

(! 870)-> clj -Sdeps '{:deps {polyfy/polylith
                      {:git/url   "<https://github.com/polyfy/polylith>"
                       :sha       "0a29ee8fc800c1b055552d19c5a1401cc51c42cc"
                       :deps/root "projects/poly"}}}'
Clojure 1.11.0-alpha1
user=&gt; (require '[polylith.clj.core.poly-cli.core :as p])
nil
user=&gt; (require '[clojure.string :as str])
nil
user=&gt; (loop [words (vec (str/split (do (print "poly&gt; ") (flush) (read-line)) #" "))]
         (when-not (= "quit" (first words))
           (apply p/-main (conj words ":no-exit"))
           (recur (vec (str/split (do (print "poly&gt; ") (flush) (read-line)) #" ")))))
poly&gt; info
  stable since: 7701e4c | stable-sean

  projects: 2   interfaces: 17
  bases:    2   components: 17

  project            alias  status   dev
  --------------------------------   ---
  google-search-job  gs      ---     ---
  development *      dev     ---     ---
...
poly&gt; test :dev
Projects to run tests from: development
...
quit
user=&gt;

2
tengstrand 2021-06-10T07:48:05.102700Z

Nice implementation!

seancorfield 2021-06-10T06:44:48.102Z

The prompt-and-read expression should be a function of course but this means the startup overhead of running the tool is avoided. Perhaps something like this could be added to the poly-cli as some sort of interactive command? (`poly interactive`)

1⭐
tengstrand 2021-06-10T07:45:15.102400Z

Yes, not a bad idea, and this actually something that is supported by the Leiningen based version https://github.com/tengstrand/lein-polylith#prompt (I’m not saying that people should start using that tool though!).

seancorfield 2021-06-10T16:12:08.109200Z

I’ll probably make a wrapper for use at work, for the time being. I have the paths/deps checking code up and running too, so I’ll probably wrap the check command in interactive mode to run that report. I’ll share that once I have it cleaned up.

1👍
tengstrand 2021-06-10T07:45:15.102400Z

Yes, not a bad idea, and this actually something that is supported by the Leiningen based version https://github.com/tengstrand/lein-polylith#prompt (I’m not saying that people should start using that tool though!).

tengstrand 2021-06-10T07:48:05.102700Z

Nice implementation!

2021-06-10T08:25:22.104600Z

Thanks for sharing the Polylith architecture! I really like some ideas and I’m trying to explore the ones I don’t understand yet. I hope you don’t mind me asking some questions here 🙂

2😎
2021-06-10T08:25:34.104800Z

When adding a component it says "Remember to add src, resources and test directories to 'deps.edn" .Since we are using tools.deps, why don’t we rely on a deps.edn file? This would make it also easier to isolate projects?

2021-06-10T08:26:10.105200Z

I am still wrapping my head around the interface approach and I’m wondering if working with protocols isn’t easier. This wouldn’t require swapping classpaths. I need to explore this more I guess

2021-06-10T08:26:56.105900Z

And I’m curious if we could make a Babashka version of the poly tool to improve startup

1👀
ericdallo 2021-06-12T18:09:16.123100Z

LMK if you need help if you need to setup the poly tool using GraalVM 🙂

ericdallo 2021-06-12T18:09:26.123300Z

#graalvm may help as well

tengstrand 2021-06-14T10:25:40.127400Z

Yes, if you want to look into this, that would be great @ericdallo!

2021-06-10T08:27:01.106100Z

That’s it for now 🙂

2021-06-10T08:30:18.106800Z

E.g. I’m used to create components (the Stuart Sierra version of it). These components implement a protocol and switching between dev and production is switching a component in the system configuration

2021-06-10T08:42:39.107Z

One argument I can think of this that it doesn’t worked well for test dirs

tengstrand 2021-06-10T09:59:41.107500Z

I guess you are working from the master branch where we have to add the paths for the bricks that we use in each project (this is also what we recommend at the moment). In the https://github.com/polyfy/polylith/tree/issue-66 we instead let each brick (component/base) have its own deps.edn file that can be included by the projects using the local/root syntax. We are working hard to get this branch into a state where it can be merged back to master . Hope this answered your question.

2021-06-10T10:01:16.107700Z

Ah great! I’ll have a look. Thanks!

1👍
tengstrand 2021-06-10T10:11:03.107900Z

Polylith takes another approach where each project is just a set of bricks, where each brick is a block of code. Once the bricks are put together they form a single codebase where all building blocks automatically “connect” to each other, and no other configuration is needed. You can get an idea how a Polylith workspace looks like together with Stuart Sierra’s components https://github.com/seancorfield/usermanager-example/tree/polylith.

tengstrand 2021-06-10T10:15:18.108100Z

Yes, that would be great (and I have had the same ide)! Maybe someone in the community could help out with this, and maybe create a PR, because there are a lot of other tasks that need to be done before this can be prioritised.

1👌
2021-06-10T10:26:32.108400Z

Thanks, i’ll have a look! I’m sure I’m not grasping everything yet

1👍
seancorfield 2021-06-10T16:12:08.109200Z

I’ll probably make a wrapper for use at work, for the time being. I have the paths/deps checking code up and running too, so I’ll probably wrap the check command in interactive mode to run that report. I’ll share that once I have it cleaned up.

1👍
seancorfield 2021-06-10T16:19:29.109400Z

@jeroenvandijk Even on the issue 66 branch, you still have to manually add paths to the workspace-level deps.edn file but Joakim has talked about maybe adding a sync command to add things to the :dev/`:test` aliases in that file, and I have some code I plan to release shortly that at least does a check to highlight anything that is missing (you need to add :extra-deps to :dev to match any :deps from components that you add — and that’s always going to be partially manually since it is up to the developer to add new deps to components as they are needed).

1👍
seancorfield 2021-06-10T16:22:02.109600Z

It seems like an FAQ when folks first start looking at Polylith. The “problem” with a protocol is that you need a common first argument to dispatch on. With Polylith’s purely “functional interface” approach, that’s not needed: they are just regular functions. I also asked about this when I got started but now the functional interface approach seems natural.

1👍
2021-06-10T17:03:38.110Z

Thank you @seancorfield

seancorfield 2021-06-10T18:05:22.111800Z

I’ve tidied up my little interactive poly “REPL” and added the :dev/`:test` deps/paths check — happy to donate it to the Polylith project if there’s interest:

(! 875)-&gt; clojure -X:poly
OpenJDK 64-Bit Server VM warning: Option --illegal-access is deprecated and will be removed in a future release.
Welcome to Polylith!
poly&gt; check
The following paths appear to be missing from :dev &gt; :extra-paths
- components/crud-form/src
- components/host-services/resources
The following dependencies appear to be missing from :dev &gt; :extra-deps
- com.google.apis/google-api-services-searchconsole #:mvn{:version v1-rev20201209-1.31.0}
- exoscale/coax #:mvn{:version 1.0.0-alpha12}
The following paths appear to be missing from :test &gt; :extra-paths
- components/environment/test
- components/safe-coercions/test
OK
poly&gt; quit
The check command runs my dep/path check and then runs poly check. All other commands are just passed as-is to poly.

seancorfield 2021-06-10T18:20:09.111900Z

Our :poly alias:

:poly {; for our development/logging operations:
         :jvm-opts ["-Dclojure.core.async.go-checking=true"
                    "-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory"
                    "-Dlogged-future=synchronous"
                    "-XX:-OmitStackTraceInFastThrow"
                    "--illegal-access=warn"]
         :extra-paths ["development/src"]
         :extra-deps {polyfy/polylith
                      {:git/url   "<https://github.com/polyfy/polylith>"
                       :sha       "0a29ee8fc800c1b055552d19c5a1401cc51c42cc"
                       :deps/root "projects/poly"}
                      org.clojure/tools.deps.alpha
                      ;; the add-libs branch
                      {:git/url "<https://github.com/clojure/tools.deps.alpha>"
                       :sha "241cd24c35ba770aea4773ea161d45276e5d3a73"}}
         :exec-fn ws.poly-wrapper.interactive/repl
         :main-opts ["-m" "polylith.clj.core.poly-cli.core"]}
(issue-66 branch head). clojure -M:poly will run the regular poly tool “one shot”. clojure -X:poly will run my interactive wrapper. EOF or quit will exit.

seancorfield 2021-06-10T18:24:26.112100Z

(my deps-checking code currently relies on some parts of t.d.a that aren’t present in the t.d.a version poly uses, although it could use "0.11.922" instead of the add-libs branch version)

seancorfield 2021-06-10T19:27:05.113400Z

I can no longer figure out what problem I was trying to solve at the time I wrote the above so I’m not sure whether or not profiles would address the issue. For now, things are working “as expected” so I’m all good. I think this was mostly around — quite literally — a resources folder that should be part of the :dev context but didn’t seem to be picked up when running test :dev, but I solved it by specifying an absolute path in my environment variable. If I ever run into a similar issue (or somehow manage to repro what I had tripped over) I’ll let you know!

1👍
tengstrand 2021-06-10T19:27:51.113600Z

Okay, nice work! I think this functionality could be part of the poly tool as its own command, e.g. prompt. I’m very curious to see your code, and I will put it up on my todo list to implement. It’s really cool what you can do with tools.deps CLI. It’s so composable!

seancorfield 2021-06-10T19:29:01.113800Z

Here’s the ws.poly-wrapper.interactive namespace from the development/src folder — feel free to incorporate whatever you want directly into poly:

seancorfield 2021-06-10T19:30:47.114200Z

It doesn’t care if :dev/`:test` contain more paths/deps, only if they contain fewer.

tengstrand 2021-06-10T19:40:17.114400Z

Ok, cool. I saw that you use t.d.a/slurp-deps instead of just slurp and read-string (as I currently do). I had a look at the t.d.a/slurp-deps and it does canonical-all-syms. Need to have a look what useful stuff that function does, and maybe I can use that in the poly tool instead.

seancorfield 2021-06-10T19:43:47.114600Z

I would definitely recommend updating to a more recent t.d.a than you are currently using and leveraging the functionality it provides for reading/merging deps.edn files.

tengstrand 2021-06-10T19:44:24.114800Z

Good idea.