Re: OO Design induces an existential crisis



kj <socyl@xxxxxxxxxxxxxxxxx> wrote in
news:dak130$a51$1@xxxxxxxxxxxxxxxxx:

> In <fnbpc194knu1gih31ho79695k0q9ttk89v@xxxxxxx> Rick Elbers
> <rick.elbers@xxxxxxxxx> writes:

> The "Just list candidate classes" line reminds me of Nijinksy's "I
> just leap and stop in midair". Figuring out the candidate classes
> is hell for me.

Analysis paralysis? I suffered from this terribly for a while. OO gives
you many choices and you freeze up trying to figure out which is best.

A: The best choice is to figure out how your clients will use the object
and go from there. Don't worry about being right/best. Worry about
working, worry about writing tests that prove its working, then worry
about improving. Its a bit like my father always says: "Look after today
and tomorrow looks after itself :-".

> Or I should put it differently: when I look at
> the "candidate classes" that OO experts come up with I am utterly
> mystified, like someone who just saw an elephant being pulled out
> of a hat.

OO experts aren't always right. Or at least they're solving something
slightly different than what you need, which can make a big difference.
Sure there is creativity there, and you don't see how they made that
leap, but they got that creativity by trial and error and practice, just
as you will.

Might read up on patterns. Patterns are shorthand for prior creative
ideas. Know your patterns and most things things are just one-offs or
combinations of them. If you can "see" patterns in the problem, you'll be
creative.

> My first recollection of this is when I learned about the general
> MVC idea for the first time. I understood the scheme right away,
> but I was (and remain) puzzled/amazed that anyone could have come
> up with that particular way to break up the problem. But that's
> not the worst of it, since, who knows, maybe after thinking about
> the problem for some time I could have come up with something
> remotely resembling the MVC classes. But I am *certain* that not
> in a MILLION YEARS would I have been able to come up with the
> particular set of "responsibilities" for these classes that
> characterizes the MVC scheme. (I'm using the term "responsibilities"
> losely to refer to both "who does what", and "who *knows* what".)

MVC isn't simple, as has been stated. But when I first read about MVC I
had no code to go by and the articles were vague. So I wrote it myself
and came up with something different and, I think, better. At least for
my needs. And I wasn't a great programmer, but it did give insight into
the fact than somebody else's published solution is not necessarily
better than my own. Simply thinking about "separating concerns" or even
simpler, look for common code and then extract it. Be brutal in your
quest for extracting commonality and simplifying your code and you'll go
a long way there.

> I can think of three possible explanations for this, in increasing
> order of desirability:
>
> 1. The MVC scheme was just a stroke of genius (end of story, time
> to find a new job).

There *are* geniuses out there. Some are like you and me, only 10 times
better. Some are from Venus. It happens. But MVC was incrementally
developed, not pulled out of thin air.

> 2. The MVC scheme was the outcome of much blind trial and error;
> after umpteen failed alternatives, *uncannily*, MVC proved to
> be the best ("just trust us: it works; we are not sure exactly
> why, but it works").
>
> 3. The MVC scheme is the logical consequence of a series of design
> *principles* that, it just so happens, I don't yet know.

4. MVC is a logical consequence of a series of observations and
improvements. We call the results "principles", but they were simply
bright ideas to de-spagetti-ize some existing code that slowly but surely
simplified the system.

> Of course, I hope the answer is 3, but after years of searching
> (and reading more descriptions of MVC than one can shake a stick
> at) I have yet to find what these principles are. And no, I'm not
> referring to the boilerplate OO principles of abstraction,
> encapsulation, inheritance, blah, blah, blah. One can follow
> *these* principles religiously and *never* even *suspect* the
> classes let alone the assignment of responsibilities that
> characterizes MVC.

Oh yeah :-) The best programmer I know has officially "abandoned" OO for
"post-OO", which is simply using the best pattern for a particular
problem that happens to be implemented in an OO language. He uses unit
tests to rachet himself up and he strives to *not* design ahead, rather
to build the simplest solution at the given moment and adjust it later as
needed. Celebrate when you find you can throw code away. If the entire
problem can be solved in one class, do it that way. Extract
abstractions/commonality as needed. Repeat...

Ok, he is a pro who does the right things anyway, but there is much to be
said for doing things simply and not worrying about all that other OO
stuff. I've seen so much crap that is nothing but dead albatross weight
simply to follow the "OO rules". Written by twits who read all the books
and never ever *used* the crap they wrote. *Use* the crap you write and
you'll be a great OO programmer in no time :-) I'm serious.

I know its definitely an acquired skill, but one learns to "listen to
one's code". What is it telling you? Does it want to be abstracted? Does
it want you to create a superclass and shove all that common stuff up?
Does it want you to straighten out its clumsy mess of an inheritance
hierarchy? Listen to your code and *care* about it. With that attitude it
won't take long to be in the top 95+ percentile or more. (Higher perhaps.
It seems to me that most programmers write crap and don't care.)

Don't worry that you would never have invented MVC by yourself. Think
about the problem then write your own code that solves the same issues.
Bet you get something different, and bet it works better for you than
adjusting your style to MVC. Or maybe not, but you'll have a much deeper
understanding of MVC and you'll have much more confidence because you'll
hae done it yourself. And if you didn't "do it" (i.e., you failed), then
throw it away and try again. Do this enough times and you'll have
sufficient depth to discuss the issues with the other so-called experts.

> Here's one more, more mundane, example, which is occupying me at
> the moment. I decided, by way of exercise, to design a collection
> of classes to represent and manipulate graphs (as in vertices and
> edges). Of the "candidate classes" I initially thought of, the
> main ones were Vertex and Edge. These seemed like a no-brainer.
> After all, mathematicians defined a graph as a set of vertices and
> a set of edges between these vertices.
>
> I wrote the tests, implemented the classes and wrote a few programs
> with them, and they seem fine. But then I looked at a few standard
> implementations of graph classes and was surprised to see that,
> although *all* of them included an Edge class, not a single one of
> them had a Vertex class! Moreover, all of them include a Graph
> class, which I did not include because my Vertex class encapsulates
> all the information (i.e. the vertex' neighbors) necessary to fully
> describe the graph.

1) This is one of the harder OO problems. Really it is. The uses are so
diverse.

2) I've seen tons of Graph/Vertex/Edge packages and mostly they suck.
Written by people who also wrote the Fortran libraries to do the same
thing. (This would be me too, btw :-)

3) There is a redundancy of information between the Vertex and Edge, so
some people drop the Vertex. Ok for some problems, inferior for others.
I've written some graph packages that used edges then added vertices.
I've written some graph packages that used vertices then added edges.
I've written some graph packages that used both.
I've written some graph packages that used both, then I've gone back and
eliminated the vertices.
I've written a great deal of really *** graph code. Over and over again.
I've thrown away a great deal of graph code, some good, some crap. Now
I'm an OO expert...I write nothing until I know what its for.

4) The Graph class is an interesting one. This is OO901, but even OO
"needs a place to stand". A graph is not just a collection of edges
and/or vertices in the same way that a power plant is not just a
collection of pots and pans connected by pipes. You might be able to do
without the Graph object, depending on your application, but what if you
added a Graph to your package? Would it simply things or complicate
things? Generally speaking, for the hard stuff it helps, because some
graph attributes belong to the graph and not to the vertices or edges.

5) Today I'd implement my Graph/Vertex/Edge classes as a Visitor pattern,
which is radically different from what you've probably seen. Am I a
genius:-? Well, yes, but only because I sweated that particular pattern
for many months and learned new potentials for it. I'd sweated graphs and
I'd sweated visitor, then I realized there was some common sweat. I
wouldn't have seen the match between the two unless I'd sweated the two
separately. What I'm saying is that its the genius of perspiration, not
the genius of inspiration. IOW, you can learn it too if you practice man
practice.

> I can come up with possible explanations for why all these
> implementations avoided using a Vertex class, but they are just
> guesses. In reality, I have no clue.

What was the purpose of your code? To be the be all and end all of Graph
theory? Or to model/solve some particular graph problem? If the former,
that was your problem. If the latter, use your code and use their code.
Is their code so much better for *your* problem? Doubt it. Bet they
generalized the code and added a bunch of extra stuff you don't need and
shouldn't want.

> As you can see, listing the candidate classes, and their
> responsibilities, is, as far as I can tell, black magic.

As an OO 402 comment, my candidate classes tend to be better when I don't
think of them as such. IOW, candidate classes are born, not made.
Mystical BS ahead, but the code gives you the candidate classes
eventually if you listen and work hard to KISS. You do have to rename
them again and again as they morph, though.

>>Don't go into details considering frameworks you
>>use, just mention the classes/ responsibilities to be used with the
>>responsibilities of your domain classes. Don't even try to mention
>>methods of the framework classes.
>
> It's interesting to read this, because even though lately I've made
> a conscious effort, during the design stage, to stay as far away
> as possible from specific implementation details, I still devote
> much thought to the methods each class will support. The reasoning
> goes like this: "it's taking me aeons to design these classes, so
> at least let's design some halfway decent APIs *now*, and ***hope***
> that, with enough *refactoring* I will (asymptotically) arrive at
> adequate implementations for them." Of course, when I say I think
> about these methods what I mean is that I think about their names
> and their signatures, and how they complement each other, not about
> their guts.

Thinking about what methods each class will support is a red flag to me.
Usually leads to a bunch of methods that are never used and simply adds
to the complexity of each class, IME. *Wait* until you need a method,
then write it in the most logical class at hand or make a new one. Then
clean up. *Never* write a method that you think you're going to need or
will "round off" your class. It'll just add dead weight to carry around.

>"it's taking me aeons to design these classes, so
> at least let's design some halfway decent APIs *now*, and ***hope***
> that, with enough *refactoring* I will (asymptotically) arrive at
> adequate implementations for them."

This isn't good :-) (1) Don't take eons to design them, wait until you
need them. And especially don't write the code to provide them until you
need them (because you might not need them after all). (2) Halfway decent
(or even wholeway decent) APIS without anything *real* that uses them are
doomed to failure.

BTW, once I do have a set of classes (coded or UMLed in my head), I find
it very useful to draw them on a large whiteboard and walk through
scenarios with others. And each new scenario gets the same treatment,
perhaps requiring class refactorings. If you can talk about your classes
as if they were people who cooperate well together, you're on the right
track :-)

Good luck. I can relate to everything you say. Hope you can wade through
all the different opinions and not be more confused and frustrated than
when you started :-) If there was one thing you could do to get better
fast, it would be to find a great programmer and work at his/her side. It
might be a very uneven pair programming, but you cannot learn better than
watching over the shoulder of someone who's good.
.