1

Normally I expect that once an object is constructed, it should be ready for use, period. No two step construction. If you need calling two constructors for using an object something is very wrong... right?

class Contact
  attr_accessor :auth_token

  def initialize(contact_hash)
     ...
  end

  def edit(...)
     auth_token.can! :read, self
  end
end

token = AuthorizationToken.new(session)
contact = SomeService.get_contact(...)

contact.edit(...)
# raise error because auth_token is not set

contact.auth_token = token

contact.edit(...)

The code above represents my current dilemma: I want SomeService to give me Contact objects, but I do not want that service to be concerned about an existing session, or authorization at all.

My current approach is adding this extra class:

class QueryService
  def initialize(session)
    token = AuthorizationToken(session)
  end

  def get_contact
    contact = SomeService.get_contact(...)
    contact.token = token
  end
end

contact = QueryService.new(session).get_contact(...)
contact.edit(...)

This solution gives me the most freedom to use authorization concerns inside the core domain object Contact, implement them in an external class AuthorizationToken and implement services that are not concerned about the current user session SomeService.

However the two step construction is killing me. It feels strange: An object that is not fully initialized for some operations???

This is not a plain case of dependency injection, but more exactly a context injection. So most of the articles about avoiding DI in Ruby do not really solve my problem. I am wondering if there is a more Ruby way to solve this, or this is just as clean as it can get.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
SystematicFrank
  • 16,555
  • 7
  • 56
  • 102

1 Answers1

0

Looks like your Contact class serves two purposes - storing contact data and doing some authorized requests - so yes it does violate the Single Responsibility Principle.

This could be fixed by splitting the Contact class into two - one maybe a Struct or even a plain hash to store the data, and the second that has does the requests.

And I think the most Ruby way to do it would be to return hashes from SomeService and instantiate with Contact.new(data, auth_token) later on.

Leonid Shevtsov
  • 14,024
  • 9
  • 51
  • 82
  • I've just added `self` to the call of auth token to show my use of ioc to reduce the burden of authorization logic. Actually `Contact` is not a plain storage model, but a domain aggregate root. I did not want to mention DDD trying to make my question easier. I am more curious to find out if the use of two step initialization is a code smell. – SystematicFrank Feb 02 '15 at 11:29
  • After some experiments I quickly noticed that the authorization object in my example was a totally insane idea and clearly headed towards trouble. That was a very bad example! – SystematicFrank Feb 02 '15 at 16:24
  • Although this answer does not directly answer the question in the title, a two stage construction leads directly to breaking the SRP since there is a transition of what the object can do before and after the second initialization. A sure break of the SRP seems to indicate that two stage construction is actually a code smell – SystematicFrank Feb 02 '15 at 16:27
  • @SystematicFrank Oh! Well, from a DDD perspective the service should definitely return Value Objects and not Entities, and that should free the VO from the dependency on the token. – Leonid Shevtsov Feb 02 '15 at 17:11