We are a user experience design and software development firm
Hire us to design your site, build your application, serve billions of users and solve real problems.
So, while most of you were off celebrating the holidays, Dietrich was off killing a duck, or at least Duck Typing. Personally, I always thought that the goose was the traditional holiday bird.. shows what I know.
Deitrich's argument is that Duck Typing does not allow "Dead Duck Typing", being able to restrict access to part of an object's state or functionality. The classic case here is keeping a display layer from getting at the persistence layer. (Maybe we can call this Stephen Colbert Typing, since you're declaring part of the object as "dead to me"...)
Dietrich closed his post with:
Some will argue this is a Java-ism creeping into Ruby. I say this is just plain old-fashioned good OO design.
Which I think is my cue.
I understand the theoretical argument for having strict (or stricter) access control in a system, and I certainly understand why having small, high cohesion classes is a good thing. My problem is that it's very rare for me to have a practical issue in a system because of loose access control or overly generous interfaces (granted, I've had a good run of working with smart people). On the other side, I commonly find that when I'm writing a program with access control I'd like to do something more flexible with an object, but I can't, because the original writer of the class did not anticipate the usage.
Specifically on the Ruby side, it's actually not hard at all to restrict access to an object. ActiveRecord objects can easily be made read only called before being passed to a view to protect from inadvertent changes.
In the more general case, it's not hard to do something like this, which only allows certain methods of an object to be called:
class ArbitraryProxy
def initialize(object, *methods)
@object = object
@methods = methods
end
def method_missing(method, *args)
if @methods.include? method
return @object.send(method, *args)
end
super
end
end
x = ArbitraryProxy.new("abcd", :size, :gsub)
p x.size
p x.gsub("b", "---")
p x.upcase
This returns:
4 "a---cd" NoMethodError: undefined method ‘upcase’
The interesting thing is that, by and large, Rails developers don't feel the need to do this. I don't think I've ever seen an authoritative source suggest that it's best practice to make ActiveRecord objects read only before passing them to the view.
There is a Rails plugin called Liquid that enforces the use of proxy objects before being passed to the view. It's not very widely used (in part because creating the proxies is kind of a pain).
I don't see that Ruby and Rails programmers see this issue as a practical problem facing them (it helps that Ruby tends to encourage small classes in other ways). That said, there are clearly cases where you need to be extra careful. Liquid is used as user-facing templating engine for a blog tool, which is clearly a case where you'd want to limit the damage that your template writers can do.
But I see that as the exception, not the rule. Long live the Duck!
Coming Soon: Professional Ruby on Rails -- available in bookstores Mid-Februrary.
Technorati Tags:
ruby, OOAD, Duck Typing
Topics: Analysis, Best Practices, Design Patterns, Ruby on Rails
Hire us to design your site, build your application, serve billions of users and solve real problems.