This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-01
Channels
- # announcements (10)
- # aws (1)
- # babashka (19)
- # beginners (104)
- # calva (50)
- # cider (17)
- # cljs-dev (135)
- # cljsrn (56)
- # clojure (240)
- # clojure-dev (4)
- # clojure-europe (19)
- # clojure-nl (2)
- # clojure-uk (7)
- # clojurescript (22)
- # conjure (2)
- # css (1)
- # cursive (10)
- # data-science (1)
- # datomic (60)
- # emacs (2)
- # events (2)
- # exercism (1)
- # figwheel-main (3)
- # fulcro (13)
- # graalvm (5)
- # gratitude (1)
- # inf-clojure (4)
- # introduce-yourself (5)
- # jobs-discuss (21)
- # lsp (36)
- # malli (6)
- # meander (8)
- # missionary (12)
- # off-topic (14)
- # pathom (13)
- # pedestal (10)
- # polylith (42)
- # re-frame (5)
- # reagent (12)
- # reitit (3)
- # releases (8)
- # sci (10)
- # shadow-cljs (37)
- # sql (5)
- # tools-deps (6)
Any tips for getting clj -Stree
to work within a Polylith repo? The output is showing little more than Clojure’s own deps. Our setup is fairly simply, but we have a couple dozen direct dependencies.
@kendall.buchanan clojure -Stree -A:dev
-- in Polylith, your main deps all come in behind a :dev
alias.
For example, in the Polylith branch of my usermanager example:
/usermanager-example$ clojure -A:dev -Stree
org.clojure/clojure 1.10.3
. org.clojure/spec.alpha 0.2.194
. org.clojure/core.specs.alpha 0.2.56
com.github.seancorfield/next.jdbc 1.2.689
. org.clojure/java.data 1.0.86
. org.clojure/tools.logging 1.1.0
. camel-snake-kebab/camel-snake-kebab 0.4.2
com.stuartsierra/component 1.0.0
. com.stuartsierra/dependency 1.0.0
compojure/compojure 1.6.2
...
@seancorfield Thank you thank you! I was looking for how to incorporate the alias, and finding the tools.deps docs impenetrable.
We're using CircleCI at work which requires a single configuration file for the whole repository. On the other hand It would be best if polylith projects were independent of each other in every aspect, including CI/CD. https://circleci.com/docs/2.0/local-cli/#packing-a-config, which combines multiple config files into a single one but I'm not a huge fan (seems like a hack). How do you deal with this problem?
We're not using polylith (yet!) but considering switching to a monorepo approach
Both Polylith repository itself and the Realworld Example repository uses CircleCI to build/deploy. You can check out their configuration files.
Oh damn, you're right, sorry. I don't know why I didn't think of that, thanks.
No worries! Also it could be good to take a look at deployer
component in the Polylith repository. It uses api/projects-to-deploy
function to determine which projects in the workspace has changed since the last release and only deploys those projects (Although at the moment we only deploy poly, previously we had more than one deployable artifacts. The code is still there for multiple artifacts).
Oh. my mistake, we still deploy two actually, api
and poly
. So, it should be a good example 😄
If you want to calculate changes separately per project, you can do it by specifying one key per project/system in :tag-patterns
e.g.:
:tag-patterns {...
:system1 “system1-*
:another-system “another-system-*}
…that lives in workspace.edn
.
Nice, so the following could work, right? 1. Allow selective change detection by specifying custom tag-patterns in workspace.edn (i.e. assign groups) 2. build jars/docker images/whatever only for the projects that have changed 3. deploy just them
To get only the projects that have changed on the CI I personally use
clojure -M:poly ws color-mode:none get:changes:changed-or-affected-projects since:release
;; => [“api” “cli”]
Yes. We do that in our Polylith workspace at work, that contains three projects that we build separately (and tag separately).
Yes, and you can replace release
with other keys in :tag-patterns
if you want.
That's great feedback, thank you all 🙂
I think @U2BDZ9JG3 uses release
only, but we use one per project, so it depends on your needs.
Anybody have a recommendation on using "`-`" vs "`" in component names? I think I want the "
-`" in the namespace names but "``" in the file system?
poly create component name:my-name
doesn't try and use underscores for the folder structure
Oo it actually does seem to use underscores in the folder paths under src
(and test
)
Right, you get -
in the component name and the namespaces, but _
in the folders that contain the source/test code.
We have quite a few with -
in them:
(! 512)-> ls bases/ components/
bases/:
artifact-uploader-cli batch-jobs preview-web
components/:
affiliate-link configuration exceptions http-client-response seo-keyword
artifact-uploader crud-form file-system member-engagement site
billing-machine datasources gdpr messaging-sdk slack-notifications
billing-sdk date-time google-search-console safe-coercions system-properties
caching environment host-services seo-json-renderer user-attributes
Beautiful, thanks @seancorfield 🙏 makes total sense
@seancorfield Nice component naming! It’s incredible how clear a domain can become with good naming, at the right level of abstraction.
Indeed. Polylith really helps with the focus here. Hence my June article in praise of that! https://corfield.org/blog/2021/06/06/deps-edn-monorepo-3/
Indeed. Polylith really helps with the focus here. Hence my June article in praise of that! https://corfield.org/blog/2021/06/06/deps-edn-monorepo-3/
Would it be a good idea to simplify interface files with Potemkin? That is, go from
(ns polylith.component.interface (:require <etc>))
(defn foo [a] (core/foo a)
(defn bar ([b] (core/bar b nil))
([b c] (core/bar b c)))
(def my_constant core/my_constant)
to
(ns polyith.component.interface (:require <etc>))
(potemkin/import-vars
[polylith.component.core
foo
bar
my_constant])
I’m very tempted to do that too, but you loose at least the IDE documentation popups and autocompletion I guess when using the interface then
The poly
tool parses the source files to figure out which def
, defn
and defmacro
definitions they contain. It would not recognise this Potemkin
syntax. The effect would be that it thinks that all your interfaces were empty, and the different checks the tool does, that helps you keeping interfaces in sync (if you have more than one implementation of an interface) would have no effect. If this is important, you could write an issue that you want the tool to support this way of defining interfaces.
Huh, I had forgotten about the poly
tool.
I also think it has a value that all Polylith codebases look the same (or at least similar) which makes it easier for new developers to understand a codebase.
@U0295UQ75FG There are several benefits to the interface/impl separation: • You can order the interface functions alphabetically (no worries about calling fns before they're defined) • The interface functions do not need to have the same signatures as the impl fns -- so you can have better ergonomics and more IDE-friendly arglists • You have a simple ns that anyone can easily read, without worrying about big function bodies getting in the way: the interface can be about names and docstrings and IDE-support (arglists etc). • Tool support: stuff like Potemkin makes that harder in all sorts of ways
In one of our interfaces, we have friendly named functions that all call down to a single generic API-invoker in the implementation: the interface allows for a much cleaner API for users that hides the actual detail of how parameters are passed to the API invoker under the hood. There's no fixed rule that says interface to impl should be 1:1 delegation.
Trust me, once you've been using Polylith for a while, you will stop worrying about trying to "make interfaces simpler" 🙂
I realized that was why I pushed for <top-ns>.<brick-name>
to be allowed as the interface, with the .interface
suffix, but as I used Polylith more, I came to see that having .interface
there was actually a very useful signifier -- especially as we're working with a mixed codebase that is migrating to Polylith: at a glance we can identify new, Polylith component namespaces from older, legacy subproject namespaces (because the former always have .interface
on the end).
> There's no fixed rule that says interface to impl should be 1:1 delegation. My migration process has caused a 1:1 delegation from interface to impl... But point taken.
An example of the above:
;; Billing Admin API bridge
(defn freeze-membership
"Given a BillingSDK component, an AzureAD token, and a member ID,
POST to the Billing Admin API to freeze a membership."
[sdk azure-token member-id]
(impl/post-to-api sdk :admin azure-token (format "/freeze/%s" member-id)))
(defn thaw-membership
"Given a BillingSDK component, an AzureAD token, and a member ID,
POST to the Billing Admin API to thaw (unfreeze) a membership."
[sdk azure-token member-id]
(impl/post-to-api sdk :admin azure-token (format "/thaw/%s" member-id)))
(defn cancel-membership
"Given a BillingSDK component, an AzureAD token, and a member ID,
POST to the Billing Admin API to cancel a membership."
[sdk azure-token member-id]
(impl/post-to-api sdk :admin azure-token (format "/cancel/%s" member-id)))
Client code doesn't need to know URLs. Impl code doesn't need to know about the actual API functions.
(we're doing our migration manually so we can improve the naming, modularity, and structure of the code as we do it)