This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-23
Channels
- # announcements (8)
- # babashka (12)
- # babashka-sci-dev (6)
- # beginners (62)
- # biff (5)
- # calva (4)
- # cider (2)
- # clj-commons (8)
- # clj-kondo (17)
- # clj-yaml (40)
- # clojars (3)
- # clojure (117)
- # clojure-europe (122)
- # clojure-nl (5)
- # clojure-norway (20)
- # clojurescript (10)
- # consulting (1)
- # datomic (65)
- # events (15)
- # figwheel (1)
- # fulcro (4)
- # lsp (15)
- # mount (15)
- # music (1)
- # off-topic (53)
- # polylith (12)
- # releases (3)
- # shadow-cljs (13)
- # sql (1)
- # test-check (8)
- # xtdb (31)
Hello everybody. I've followed polylith for some time and I'm ready to bite the bullet with some internal greenfield project. One question: I'm quite fond of integrant as a DI management tool, but it seems to me that this approach can be at odds with polylith. Does someone has any experience in this area? Thanks in advance
It’s ok to combine them like I believe many do already. They are complementary (just like mount, component, clip etc). Someone else asked a similar question https://clojurians.slack.com/archives/C013B7MQHJQ/p1645779670809589
I use Polylith with donut-system, which is quite similar to integrant. I don't think these DI tools are at odds with polylith at all, they address different concerns. I think of Polylith as a static code structure approach, whereas I use donut/integrant to (per polylith project) configure and manage the runtime state of a selection of polylith components.
you will end up having with integrant system per project. For development, it’s bit messy if you want to start a repl from the polylith root. We have:
1. a user.clj
under development that has functions to zoom into a project, e.g. (dispatcher)
to jump into a dev.clj
ns under a dispatcher project
2. in each dev.clj
, there is integrant-repl kinda tools to start, reset, stop the system
3. you can’t call tools-namespace refresh (which is a big downside IMO) as all the code (projects, bases, components) are available into the root repl, so it would load all the code. Ideas welcome on how to fix this.
e.g. to start one project locally:
make repl
$ (dispatcher)
dispatcher.dev $ (reset)
dispatcher.dev $ ;; running
@U055NJ5CC Those are helpful techniques, thanks. About number 3, I understand (maybe I'm wrong, still learning) that since projects are different deliverables, one could start different REPL, each one with its own set of dependencies, so reload wouldn't be a problem. Don't understand why one would start an REPL at the project root. Again, I'm still learning, so most probably missed something.
As was explained above, there's no interference in using integrant and polylith together. After all, I think polylith is a way of structuring codes in one repository and integrant is a small framework for constructing specific project. Few things to think carefully, however, are
• Where should components be initialized? (where should ig/init-keys take place?)
◦ My decided to put those codes within interface namespace of each components of interest when necessary. The reason is because it is simpler; all a base needs to do is to require the interface and it will automatically be taken away by the integrant system of the base.
• How to compose the top-level deps.edn?
◦ We have separate user.clj for bases with integrant (as @U055NJ5CC did), and aliased them separately as well to segregate the environments. Our :dev
alias has rest of the components or bases that do not use integrants.
Multiple project REPLs vs single root REPL is just a question of development experience. I'm in the same project as Tommi, and we've tried to make the single REPL experience work, which it does for the most part. Maybe we should experiment with having multiple project REPLs. To be honest I'm not sure how well Cursive supports that. It's nice to have a single REPL that has everything in scope - that's the reason to have the root repl.
@UCQGNA673 @U055NJ5CC Yes, I can see now the value of a single root REPL (I was wrong about using multiple REPLs, as expected). Also still don't understand the problem with reloading. Is it that there may be too many classes? Conflicts with bricks that implement same interfaces? Or is something else?
@U01TFN2113P That advice seems really userful, thanks a lot
After all source code is loaded from app projects, bases and components - the state of the system is basically undefined
due to the imperative core of clojure: all side-effects from loading namespaces have been applied. These include:
• all defmethod
s have been registered -> many apps and libs use these, e.g. compojure-api, these can clash. if anyone calls methods
on an multimethod, you see them all
• all extend-protocol
s are run, as an examples how Cheshire serializes different types, see https://github.com/dakrone/cheshire/issues/77
• all specs have been registered
• if mount is used, all mount-things have been loaded
• etc.
I think that all side-effects are run in undefined order, so the state could be anything if there are clashing uses of the global registries (spec, multimethods, protocols, application level things etc)