user2158382
user2158382

Reputation: 4510

Rails why use delegate?

I am currently learning about delegate and the Law of Demeter, and I can't seem to find a good example of where using delegate would actually even be useful.

I want to find an example related to my project, since I have to give a presentation. The only line of code that I found that could possibly be breaking the Law of Demeter is the following:

@game.promotions.find_by_promo_type("cross")

The model Game has_many Promotions and it is reaching across another model to execute a find call based on promotions attribute promo_type. From my understanding this is a violation of the Law of Demeter, and I should fix this by using delegate as so:

class Game < ActiveRecord::Base
   has_many :promotions

   delegate :find_by_promo_type, :to => :promotion
end

Can you give me an example where this would actually be useful besides "the Law of Demeter says so".

The only thing I can think of, is for some reason I wanted to change the name of promotions to promos, then the solution would be useful because I would only need to make the following change and :find_by_promo_type will still work for Game

class Game < ActiveRecord::Base
   has_many :promos

   delegate :find_by_promo_type, :to => :promos
end

The only thing is, I believe this argument is flawed. If I were to change a models name, I would also have to refactor code in many other places that don't even break the Law of Demeter. It's hard to believe that this is all the Law of Demeter can accomplish in regards to this example.

Can somebody please help me understand this.

Upvotes: 4

Views: 1553

Answers (1)

jasonyork
jasonyork

Reputation: 251

Using delegate can have the advantage of abstracting the implementation of how something is done. In your example, it's not so much about allowing you to change the name of promotions to promos. It's about being very purposeful about what you expose to the "outside world", or, the API of your object. Objects that talk to Game shouldn't need to know that you're using another ActiveRecord model to retrieve associated Promotions. It can add unnecessary coupling.

All LoD violations aren't necessarily bad, but they can act as a code smell, and you should take pause when you see them. You need to balance the cost of removing the LoD violation against the potential cost and likelihood of change to your object's API.

I would highly recommend reading Chapter 4 of Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz. It covers this subject very well and states that: "Using delegation to hide tight coupling is not the same as decoupling the code."

In your case, you may want to think about it more from the perspective of the caller and what message it should be sending to Game. Maybe it should just be calling Game.cross_promotions instead of reaching into Game to call a method on another object, regardless if it's delegated or not.

Upvotes: 6

Related Questions