nPn nPn - 4 months ago 7
Ruby Question

Is there a more ruby idiomatic way to remove creation of configurable object dependencies?

I am trying to clean up some old code, remove dependencies, and make it more testable.

When I find situations like the following, where a parameterized object is being created in a method. For example in this code:

class Bar
def initialize parameter
@parameter = parameter
end
end

class Foo
def initialize some_parameter
@some_parameter = some_parameter
end
def some_method
...
...
bar = Bar.new parameter ## here is the dependency I would like to remove
...
end
end


I have been creating a factory class and injecting it into the constructor and then using that to create the instance, as shown here:

class Bar
def initialize parameter
@parameter = parameter
end
end

class BarFactory
def create parameter
Bar.new parameter
end
end

class Foo
attr_reader :bar_factory
def initialize some_parameter, bar_factory: nil
@bar_factory = bar_factory || BarFactory.new
@some_parameter = some_parameter
end
def some_method
...
...
bar = bar_factory.create parameter
...
end
end


I think this is an improvement, in that I can inject a different factory for test, or inject a different factory in the future if needed. But since I find myself doing this more often, I am wondering if I am falling into some anti-pattern, or if there is a more ruby idiomatic way to do the same thing?

Most of the research I did on this generally turns up injecting dependencies into a constructor, which is what I am doing here, but in this case I am injecting a factory rather than a simple object.

Answer

I am not seeing any benefit of having a dedicated factory class in Ruby, i.e. it smells of Java-style patterns (working around the fact that classes are not first-class objects there). Why wouldn't you simply:

class Bar
  def initialize parameter
    @parameter = parameter
  end
end

class Foo
  attr_reader :barlike_class
  def initialize some_parameter, barlike_class: Bar
    @barlike_class = barlike_class  
    @some_parameter = some_parameter
  end
  def some_method
    ...
    ...
    bar = barlike_class.new parameter
    ...
  end
end