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