On 2010-06-19 09:20:26 -0700, Michael Fellinger said:
>   def open_window
>     if location.window.respond_to?(:open=)
>       location.window.open = true
>     else
>       raise("The location doesn't have any windows you can open")
>     end
>   end
> end

This is a Law of Demeter violation. The home should be responsible for 
opening its own windows.

This code makes assumptions about both the house and its windows on the 
behalf of the person (that it has exactly one window, that windows are 
opened by setting their 'open' accessor) and even then it deals with 
these assumptions inconsistently.

1) It checks for the behavior of the window without first checking for 
the existance of the window. If you really must program defensively, at 
least be consistent. Better still to not program defensively.

2) It raises a misleading (or at least ambiguious) error. Far better to 
simply try it and let the interpreter tell you where you failed. Is a 
NoMethodError on a window object really any less informative? Given the 
unnecessarily complex code path (because of the Demeter violation), I 
would argue that it is more informative.

In any event, you shouldn't be violating Demeter in the first place. 
The following Law of Demeter violation better illustrates the problem:

class Person
  attr_accessor :wallet
end

class Store
  def accept_payment(person, amount)
    person.wallet.amount -= amount
  end
end

NB: I actually originally wrote it as person.wallet.withdraw(amount) 
(because I instinctively hide state and expose behavior in cases like 
these) and then realized that this is one less Demeter violation than 
the original example code.

People should be allowed to make payments themselves. I don't want the 
store reaching into my wallet and just taking my money. I *certainly* 
don't want the store reaching into my wallet and then telling me how 
much money I have when it's done.

class Store
  def accept_payment(person, amount)
    person.pay(amount)
  end
end

This lets me decide where I keep my money, how I pay and if I can pay at all.

Furthermore, allowing assignment to the window's 'open' accessor lets 
client code do `window.open = [1,2,3]` and other such nonsense. A 
window has exactly two states and its behavior should be modeled in a 
way that enforces this relationship and keeps its state hidden behind 
an interface, not by allowing client code to set its state in arbitrary 
ways. Window#open and Window#close.

The home should delegate window opening and closing to its window. The 
person should ask the home to close its window. Or the person should 
know about the window, which makes more sense in the real world but 
less sense in this OOP system.

Hopefully we can avoid making concrete OOP mistakes even while we're 
answering completely hypothetical OOP questions.

Also, can someone please write me a Person#sudo_make_me_a_sandwich!

-- 
Rein Henrichs
http://puppetlabs.com
http://reinh.com