Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to do "dependency injection" of a component? #511

Closed
filipencopav opened this issue Sep 25, 2024 · 1 comment
Closed

How to do "dependency injection" of a component? #511

filipencopav opened this issue Sep 25, 2024 · 1 comment

Comments

@filipencopav
Copy link

filipencopav commented Sep 25, 2024

Let's say we have the following setup:

poly create workspace name:example top-ns:example
poly create component name:db1 interface:db
poly create component name:db2 interface:db

Therefore, the following component directories (noise omitted):

components/
├── db1
│   └── src
│       └── example
│           ├── db
│           │   └── interface.clj
│           └── db1           # NOTE: added manually, see contents below
│              └── core.clj
└── db2
    └── src
        └── example
            ├── db
            │   └── interface.clj
            └── db2           # NOTE: added manually, see contents below
                └── core.clj

The contents of db1/src/example/db/interface.clj:

(ns example.db.interface
  (:require [example.db1.core :as core]))

(defn nop [x]
  (core/nop x))

The contents of db2/src/example/db/interface.clj:

(ns example.db.interface
  (:require [example.db2.core :as core]))

(defn nop [x]
  (core/nop x))

The contents of core files:

;; db1/src/example/db1/core.clj
(ns example.db1.core)

(defn nop [x]
  [:db1 x])

;; db2/src/example/db2/core.clj
(ns example.db2.core)

(defn nop [x]
  [:db2 x])

As you can hopefully see, the interface is defined 2 times. poly check says OK. Now, I add a development file pavel.clj with the contents:

(ns dev.pavel
  (:require [example.db.interface :as db]))

(db/nop :x)

As you can see, it depends purely on the interface. What is the expected output? [:db1 :x] or [:db2 :x]? I don't know. Who knows? (I ran the code above and it returned [:db1 :x], however I don't know why. Without :local/root definitions it returned [:db2 :x])

So, my question is: How is this kind of "dependency injection" handled in polylith (in general and in clojure polilyth)?
Additional: How to decide which interface implementation is used? Where are the decisions being written?

Sorry if this is already described in the documentation. If it is, then I must have missed it.

@filipencopav filipencopav changed the title How to do dependency injection of a component? How to do "dependency injection" of a component? Sep 25, 2024
@furkan3ayraktar
Copy link
Collaborator

It is explained here in detail with an example.

In a nutshell, Polylith provides swappable components by utilising aliases in tools.deps. As you noticed, you can not have two different implementations of the same interface in your development time classpath at the same time. They have the exact same namespaces, and one will override the other. Instead, you pick one of the implementations as default and create a Polylith profile, corresponding to an alias in your deps.edn containing the other implementation. You can then start a REPL either with the default profile or the other alias you added with the additional implementation.

By the way, you made a mistake in your example. Both db1 and db2 components must use the example.db.* prefix, as that is the prefix for the interface.

In the future, you can ask your questions in the Clojurians Slack to get a faster reply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants