Dependency Injection with many dependencies

Hi all, this is my first post here. I’m reading Practical Object
Oriented Design in Ruby by Sandy Metz right now and loving it, but there
are
areas of ‘dependency injection’ that aren’t quite sticking.

What’s the best way to inject *many dependencies into an object? I’m
building a class that relies on 7 Aws::CloudSearchDomain::Client objects
in order to upload data to Amazon Web Services. Based on the type of
data to be uploaded, I need to select the specific AWS ‘Client’ object
used to upload that type of data. This is a simplified example of what
I’m doing at the moment:

class Uploader
def self.build
attributes = {}

# AWS Client objects are instantiated with a table 'endpoint' as the

argument
attributes[:songs] =
Aws::CloudSearchDomain::Client.new(‘http://songs…’)
attributes[:albums] =
Aws::CloudSearchDomain::Client.new(‘http://albums…’)
attributes[:artists] =
Aws::CloudSearchDomain::Client.new(‘http://artists…’)

new(attributes)

end

def initialize(attributes)
@songs_aws_client = attributes[:songs]
@albums_aws_client = attributes[:albums]
@artists_aws_client = attributes[:artists]

end

def upload_record(aws_domain:, data_to_upload:)
# Logic in here would select the corresponding ‘aws_client’ based on
# the ‘aws_domain’ argument passed in. It would then upload the
record,
# something like client.upload_documents(record)
end

end

I got the idea of using #build from
http://solnic.eu/2013/12/17/the-world-needs-another-post-about-dependency-injection-in-ruby.html.

For argument sake, what if I had 1000 different tables and 1000
different types of AWS ‘Client’ objects? Is there a better way to go
about this?

I’ve been mulling it over and had some ideas for general improvement.
The first is creating a new class, AwsClientRetriever, whose purpose it
to store and retrieve different AWS ‘Client’ objects. I can inject that
single AwsClientRetriever into Uploader and call it in my class:
@aws_client_retriever.get_aws_client_for(table:
‘songs_table’).upload_documents(…). Simple and elegant if you ask me.

That cleans up the ‘Uploader’ class, but I’m still left with the
original problem of how to inject the 7 ‘AWS Client’ objects into a
class. My plan is to create a YAML file that has the names and endpoints
for each of the 7 clients, then I can loop through that data in the
AwsClientRetriever class to programmatically create new Client objects.
Something like:

require ‘yaml’

class AwsClientRetriever
# ‘clazz’ will generally be ‘Aws::CloudSearchDomain::Client’
def initialize(clazz:)
client_data = YAML.load(’…/aws_client_data’)

    @aws_clients = build_clients(clazz: clazz, client_data:

client_data)
end

def get_aws_client_for(table_name:)
    @aws_clients.select { |client| client[:table_name| ==

table_name}.first
end

private

def build_clients(clazz:, client_data:)
    output = []

    client_data.each do |table_name, endpoint|
        client = {}
        client[:table_name]   = table_name
        client[:client_object] = clazz.new(endpoint)
        output << client
    end

    output
end

end

I hope I did a decent job of explaining the original problem.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs