From: Dave Thomas Date: 2003-05-14T06:33:44+09:00 Subject: Re: [OO design] Objects VS Datastructures Simon Vandemoortele wrote: > Corollary: It has also occurred to me that Contact#setName(aString) > where Contact checks if the name satisfies certain > conditions might not be the best setup since a 'name' is not > string; it is much narrower than that (in my > implementation). Maybe I'd better create a Name class that > represents a 'name' object and enforces it's integrity. > Doing that for all Contact's attributes would reduce it's > responsibilities to the point where it would barely differ > from a Hash, thus exacerbating the question above. Simon: Please take this the right way, but.... it seems to me that you're writing Java, or C++, and not Ruby. Although an interesting exercise, you're not really teaching yourself the philosophy of Ruby programming. Look at the problem the other way around. Here's an exercise I go through whenever I design a Ruby program. I start by looking at the dumbest, simplest implementation, the one that would never work. For example, for the contact example, I might write: Contact = Hash c = Contact.new c[:name] = "Dave Thomas" c[:tel] = "555 1212" Then I'd say to myself: that's too simple, it could never work. Then I ask myself _why_. And I make myself answer honestly. And often I can't come up with a good answer, so I stick with the simple, dumb design, and everything just works. Sometimes, though, I come up with objections. In this particular case, my main objection is that I don't like all the brackets everywhere. So I might switch from using a Hash to using OpenStruct: Contact = OpenStruct c = Contact.new c.name = "Dave Thomas" c.tel = "555 1212" Hmm - feels pretty good. I might go with this. At some point I might discover I'd like to bundle some additional behavior in the class. That's easy: at that point, and not before, I'd change my class definition class Contact < OpenStruct def dial_phone Dialer.new.dial(self.tel) end end Pretty easy - nothing else changes. After a while, I might decide that basing my class on OpenStruct isn't optimal when marshaling, so I decide to implement the accessors myself instead. I change the class definition again: class Contact attr_accessor :name, :tel ... This happens to me all the time: I start with one implementation (in this case simply using OpenStruct) and evolve my code to something totally different (in this case totally away from OpenStruct). This is one of the things I love about Ruby: it gives me the flexibility to explore in this way at the same time that I'm writing useful code. Just for a while, forget about classes, typing, and "good design". Totally. Just code up the simplest code that could work (and surprise yourself at just how simple that code can be). Sorry to preach :) Cheers Dave