I am implementing 'service objects' as per a workshop I've been studying, I'm building a reddit API application. I need the object to return something, so I can't just execute everything in the initializer. I have these two options:
Option1: Class needs instantiating
class SubListFromUser
def user_subscribed_subs(client)
@client = client
@subreddits = sort_subs_by_name(user_subs_from_reddit)
end
private
def sort_subs_by_name(subreddits)
subreddits.sort_by { |sr| sr[:name].downcase }
end
def user_subs_from_reddit
@client.subscribed_subreddits :limit => 100
end
end
Called with:
@subreddits = SubListFromUser.new(@client).user_subscribed_subs
Or Option2 is having it as a class method:
class SubListFromUser
def self.user_subscribed_subs(client)
sort_subs_by_name(client, user_subs_from_reddit)
end
private
def self.sort_subs_by_name(subreddits)
subreddits.sort_by { |sr| sr[:name].downcase }
end
def self.user_subs_from_reddit(client)
client.subscribed_subreddits :limit => 100
end
end
Called with:
@subreddits = SubListFromUser.user_subscribed_subs(@client)
What is considered 'best practice' in this situation? Is there a reason I shouldn't be using object.new(args).method? I think it gives a cleaner service class but I'm not sure of the technicalities of this approach and if it has disadvantages.
Edit: Or option3 - I'm going about this all wrong and there is a better approach :)
In Ruby, I don't find that there's much of a difference.
I find the use of class variables in your "static" version a bit disturbing.
I think the class version might lead to more-creative re-use through subclassing, but that brings its own set of headaches unless things are designed as correctly as possible.
In many cases you'll need to keep a state for the process lifecycle, such as the client
. Instead of having it "travel" through all methods you need it, as an argument, it makes more sense to keep it as a class variable. But for the sake of cleaner syntax, I recommend to combine the two approaches:
class SubListFromUser
def initialize(client)
@client = client
end
private_class_method :new # only this class can create instances of itself
def user_subscribed_subs
@subreddits = sort_subs_by_name(user_subs_from_reddit)
end
private
def sort_subs_by_name(subreddits)
subreddits.sort_by { |sr| sr[:name].downcase }
end
def user_subs_from_reddit
@client.subscribed_subreddits :limit => 100
end
class << self
def user_subscribed_subs(client)
new(client).user_subscribed_subs # create instance of this class and run a process
end
end
end
Call as a class method:
@subreddits = SubListFromUser.user_subscribed_subs(@client)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With