Pascal J. Bourguignon wrote:
Tom Cloyd <tomcloyd@comcast.net> writes:
[...] My problem was simply that as I was trying to introduce classes into my project code, I didn't know when I really SHOULD create a class. I had gotten the impression somewhere that major methods should virtually always be reconceptualized as classes. I didn't arrive at that notion by thinking. I'd given up on that, as I didn't have enough material to work with.
But, that perception didn't really make a lot of sense. Still, I couldn't find any explicit guidance anywhere regarding the fundamental question I kept asking: WHEN is it the thing to do to make a class? I did find those two sentences in Thomas (3rd ed) - but that's sparse pickins, and I didn't find them until AFTER my weekend disaster in which I spend a pile of time converting a complex method into a class, getting completely exasperated with the experience, and converting it back. So, I wasn't overthinking at all. I was mis-perceiving, in the presence of an absence (ha!) - an absence of clear guidance about the WHEN-do-classes issue. The best sense I could make of things was that "big stuff oughta be classes" (bad idea). I didn't yet "get it" (understatement).
First you write a problem statement.
Then you identify the important words in it.
Nouns will become classes.
Verbs will become methods.
(approximatively).
The idea is that what has nouns in natural language are the objects
that have some stability in the real world, and what has verbs are the
actions.
Of course, you can have reification of the actions or the
associations, when you start to speak about verbs (notice that "verb"
is a noun, not a verb).
For example, when you write:
(def m(x)
(2 * x)
end)
you actually instantiate an object of the class Method:
(Object . method "m") --> #<Method: Class(Object)#m>
but you do that only when you're talking at a meta-level, here it's
the level of the Ruby language, not that of your problem domain.
Instead of reifying the "big stuff", you should rather try to reify
the _stable_ stuff. A Person is something that is table, from her
birth to her death. On the other hand, eating, sleeping, working,
reproducing, breathing, are temporary actions. There even are actions
that cannot be done during all the life time. For example, a baby
Person has no walk method. This method is programmed during the first
few years.
Objects encapsulate state and methods.
When your problem domain (cf the problem statement) considers a Person
only in her relations with the surrounding world, then the methods of
a Person will be Ruby methods. You won't need to reify these methods.
On the other hand, if your problem statement is to implement a Person
simulator, then it's possible that the methods of a Person need to be
reifed, so you can add, change and remove these methods. Imagine
having to write a Person simulator that starts in the baby state, and
that should evolve a walk method. In this case, you could have a
MotorMethod class, and a Walk subclass, as well as classes such as
Muscle, Bone, Nerve, etc. But these kind of classes would be named in
the problem statement (at least latently, sometimes problem statements
are brief).
Pascal,
This is a simply lovely exposition. I'll add it to the other in this very helpful thread. And, I'm returning to my code, with these thoughts in mind, to see what I can learn.
Thanks for taking the time to make these things so clear. Much appreciated.
Tom
···
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website) << sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~