# Injected Dependencies best practices

**URL:** <https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120>\
**Category:** Uncategorized\
**Created:** [August 28, 2020, 10:17pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120 "2020-08-28T22:17:50Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![paul](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/paul/32/202_2.png) [@paul](https://discourse.dry-rb.org/u/paul)\
**Post date:** [August 28, 2020, 10:17pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/1 "2020-08-28T22:17:50Z")

</div>

This seems to come up often because of how dry-container encourages DI so seamlessly, but I’m frequently running into this pattern, and I’m wondering if there might be a tool to make it simpler. First a slightly contrived code example of what I’m talking about:

```ruby
class MyClient
  include MyContainer::Import[:http]

  def initialize(credentials:, **deps)
    super(**deps)
    @auth_http = http.basic_auth(credentials.user, credentials.password)
  end
end

class MyAdapter
  include MyContainer::Import[:client]

  def initialize(model: model, **deps)
    super(**deps)
    @client = client.new(credentials: model.credentials)
  end
end

class MyCommand
  include MyContainer::Import[:adapter]

  def call(a, b, c)
    model = Model.find_by_a(a)
    adapter = adapter.new(model: model)

    adapter.do_something(b)
    adapter.do_something_else(c)
  end
end

```

I like this structure of code, because the Client only has to care about “credentials”, the Adapter works on getting the credentials from the Model, and the Commands just pass the Model to Adapter.

However, the tension lies in testing this mess. I want to “pyramid/integration-test” the whole thing, to ensure changes to the Adapter doesn’t interfere with the Commands, and its easier to just have shared “fake client” between all the tests. However, because what I’m injecting is classes instead of instances, what I struggle with is how to inject the right thing at the right time. I end up having the mock both the class and the instance:

```ruby
let(:client_class) { class_double(MyClient, new: client) }
let(:client) { instance_double(MyClient, mocks...) }

before { MyContainer.stub(client: client_class) }

```

That `client_class` double feels like a smell, but I’m not quite sure what to do about it. Times like this, I really wish ruby had partial function application, so I could do something like this:

```ruby
client = MyClient.inject(http: fake_http) # Returns a "partial class" with the
adapter = MyAdapter.inject(client: client) # dependency injected but not initialized

command = MyCommand.new(adapter: adapter)
command.call(1, 2, 3) # This finally calls `.new` on all those "partial classes"

```

This seems like something up the Dry.rb team’s alley, so I thought this would be as good a place as any to ask. Has anyone come across anything like this, or tools/patterns that might help?

---

<div class="post-metadata">

**Author:** ![andrewdotnich](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/andrewdotnich/32/51_2.png) [@andrewdotnich](https://discourse.dry-rb.org/u/andrewdotnich)\
**Post date:** [August 30, 2020, 11:25pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/2 "2020-08-30T23:25:03Z")

</div>

I think `dry-auto_inject` and `dry-system` both attempt to solve this problem. I think they call `.new` by default on the things you `Import` , so you wouldn’t have to worry about the `class_double` part in your specs. You can create `instance_doubles` as normal, then in your tests manually call` new` on the object under test.

---

<div class="post-metadata">

**Author:** ![paul](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/paul/32/202_2.png) [@paul](https://discourse.dry-rb.org/u/paul)\
**Post date:** [August 30, 2020, 11:37pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/3 "2020-08-30T23:37:44Z")

</div>

I don’t think that’s true, unless maybe you’re talking about some new unreleased version?

```ruby
class MyClass
  def foo
    "hello"
  end
end

module MyContainer
  extend Dry::Container::Mixin
  Import = Dry::AutoInject(self)
  register(:my_class) { MyClass }
end

class MyOtherClass
  include MyContainer::Import[:my_class]
  def call
    my_class.foo
  end
end

```

```auto
pry(main)> MyOtherClass.new.call
NoMethodError: undefined method `foo' for MyClass:Class
Did you mean? for
from (pry):14:in `call'

```

---

<div class="post-metadata">

**Author:** ![andrewdotnich](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/andrewdotnich/32/51_2.png) [@andrewdotnich](https://discourse.dry-rb.org/u/andrewdotnich)\
**Post date:** [August 30, 2020, 11:40pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/4 "2020-08-30T23:40:34Z")

</div>

Ah, my apologies, that’s obviously incorrect for `dry-auto_inject`.  
`dry-system`'s [Auto Register feature](https://dry-rb.org/gems/dry-system/0.17/container/#auto-registration) must be what does it.

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/solnic/32/779_2.png) [@solnic](https://discourse.dry-rb.org/u/solnic)\
**Post date:** [August 31, 2020, 7:15am UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/5 "2020-08-31T07:15:16Z")

</div>

Given that you have a dependency that in order to be instantiated needs data from the database, this is really not a good fit for auto-inject. I wouldn’t inject classes and couple objects to how their deps (an adapter in this case) are instantiated. You could have something that hides adapter instantiation and use that in your objects. I suppose we could have a feature in auto-inject that would make this easier (or in dry-system).

---

<div class="post-metadata">

**Author:** ![paul](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/paul/32/202_2.png) [@paul](https://discourse.dry-rb.org/u/paul)\
**Post date:** [August 31, 2020, 2:46pm UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/6 "2020-08-31T14:46:59Z")

</div>

@solnic Noodling on this over the weekend, I was inspired by a custom addition we’d made to Dry::Transaction:

```ruby
def self.call(*args)
  self.new.call(*args)
end

```

This allows us to inject Transactions into other Transaction both as a class or as an instance:

```ruby
class TxnB
  include Import[:txn_a]

  step :do_b 

  def do_b(a:, b:)
    txn_a.call(a: a).bind(do_b(b))
  end
end

# Invoke normally:
TxnB.call(a: a, b: b)

# In a test:
TxnB.new(txn_a: -> (**) { Success() })

# or
import_container.stub(:txn_a, TxnA.new(http: FakeHTTP))

```

Similar to this, I think I’m going to monkeypatch AutoInject to create a `.setup` method, which would return an anonymous class with the default dependencies changed to those specified in `.setup`:

```ruby
adapter = MyAdapter.setup(client: fake_client)

MyCommand.new(adapter: adapter).call(...)

```

Since `MyAdapter` and `MyAdapter.setup(...)` both return something that can be `.new`-d, in the tests we can provide either as a dependency and the code will be content.

I plan to add this to our app this week, and we’ll see how it feels to use.

---

<div class="post-metadata">

**Author:** ![paul](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/paul/32/202_2.png) [@paul](https://discourse.dry-rb.org/u/paul)\
**Post date:** [September 2, 2020, 2:06am UTC](https://discourse.dry-rb.org/t/injected-dependencies-best-practices/1120/7 "2020-09-02T02:06:28Z")

</div>

The implementation turns out to be pretty simple.

```ruby
    def self.setup(**deps)
      mod = Module.new
      mod.module_eval do |mod|
        mod.define_method :initialize do |*args, **kwargs|
          super(*args, **kwargs.merge(deps))
        end
      end
      Class.new(self) do
        prepend mod
      end
    end

```
