ABCService.new.do_foo - why not a class method?

I just inherited an RoR codebase, and in many of the controllers I see the following style of code:

ABCService.new.do_foo

I have been working on RoR codebases for quite a long time, but I fail to understand why the .new. style is used. The service classes in question do not hold any state (even with class-level variables) and the same can be achieved with self (ie class-level) methods - so, any explanation of why this style is better? To me, it looks like some java developers coded this app and "ported over" some coding paradigms from that language.

Upvotes: 0

Views: 61

Answers (2)

Fabio
Fabio

Reputation: 32445

"Right tool for the job"

Having only class method, will explicitly tell other developers/readers of your code, that this service doesn't have state.
Even better, use module instead of class, then your intentions would be clear for others and for later you.

When you need state, use instance method.
For example you can have service which accepts two arguments, first one is argument which should be used for all calls of this service, but second can be change for every call.

class AddTax
  def initialize(tax_rate)
    @tax_rate = tax_rate
  end

  def to(amount)
    amount * (1.0 + @tax_rate)
  end
end

# Usage

prices = [20, 100, 50, 49, 50]

add_tax = AddTax.new(0.24);
with_taxes = prices.map { |price| add_tax.to(price) }

Upvotes: 1

fylooi
fylooi

Reputation: 3870

Making service objects stateful as a convention has its benefits:

  • Minimal refactoring when one of them requires state
  • Easy to mock in tests without messing around with constants
  • Save brain juice on this decision when implementing a new service object

That being said, whether this is beneficial for your codebase is something you / your team need to assess as part of defining your own architectural / code style conventions.

It can be quite irritating to always have to call Klass.new.do_something. You can wrap it in a class method, eg:

class Service
  class << self
    def do_something
      new.do_something
    end
  end

  def do_something
  end
end

Upvotes: 3

Related Questions