On Nov 27, 2008, at 10:52 AM, Adrian Crum wrote:
--- On Wed, 11/26/08, David E Jones <[EMAIL PROTECTED]>
wrote:
Do you have any specific bits of messy code in mind? I
don't mean to imply that I don't believe this might
help, but how does moving the code from one class to another
clean up the code?
I didn't want to go into specifics because I didn't want to hurt any
feelings or step on any toes.
People choose to hurt their own feelings. Being sensitive and not
willing to discuss things just hurts us all... so off we go...
But here goes - using the current ModelScreenWidget.java as an
example:
1. Line 797, 899, 1236 - HTML specific code inserted into model
widget.
2. Lines 972 to 986 - lost indirection.
3. Line 1072 - non thread-safe code. Btw, after I make my proposed
changes, code like that won't even compile.
These sound like good things to address directly, and that wouldn't be
fixed by following the visitor pattern. Separating the render control
code from the modeling code might be helpful (the "rendering" code is
already separate... or should be... I haven't watched every patch
going in here as much as I should... which means sometimes things are
committed by certain people who don't review them, so the code was
NEVER reviewed).
4. Any method whose name starts with "set" - these classes are
supposed to be immutable.
Are they? There is a risk of changing things in a way that is not
thread-safe, but I don't think they were ever meant to be, or designed
to be, unchangeable.
5. Any method that pushes and pops the context MapStack - that's a
rendering detail the model widget shouldn't be concerned with.
If you mean to separate rendering from modeling, but this is more
"rendering control" than actual rendering. I certainly wouldn't want
the platform-specific rendering code to be handling this.
6. Any method that makes multiple calls to the ScreenStringRenderer
interface - the model class is trying to force a rendering sequence.
This was a problem for me a couple of years ago when I tried to do
some work on the tree widget.
I don't think we can go after complete flexibility for rendering
sequence. Specific things may need to be refactored over time as
rendering for new "platforms" is added, but while this is hard to
predict we can't just have no rendering order whatsoever.
This is just one file out of a handful, and it's the cleanest, least
offending one.
Sorry if I'm a luddite, but this seems to make the code
more difficult and makes me think things like: what does
"accept" mean, and what would a method named that
actually do? what is actually being passed into this
method... maybe that can help me understand it... oh...
what's a "visitor"?
Luddites are free to ask questions on the mailing list, just like
non-luddites.
I guess what I'm saying is that just because someone
writes up a practice and calls it a best practice or a
"pattern" doesn't mean it's always a good
idea.
In this case, it is the most appropriate pattern. It's the same
pattern Adam used in the entity condition code, and the pattern I
used for the iCalendar integration.
I wasn't referring to myself as a luddite because I don't understand
it. In fact, I'd like to think that I understand it enough and in fact
have enough experience with it to know that it is used far more than
it should be. The entity condition code is a good example of this.
The visitor pattern tends to make code difficult to follow and
understand, and therefore to debug and maintain. This is usually true
even for the person who wrote the original code. While I wrote the
original entity condition code Adam Heath is the one who refactored it
to incorporate various uses of the visitor pattern. After he did that
it took me WAY longer to work through issues in it and expand it. Now
a few years later Adam is getting back into that code and his recent
comment to me was that even he was having a hard time following it now.
I should have seen this before, but at the time I didn't have
experience with it. Now my opinion is that the visitor pattern
obfuscates and complicates code, and usually the problems that people
_think_ will somehow be solved "inherently" by using it are not solved
at all, and in fact are aggravated by using it because now things are
more difficult to track down and follow. Thinking back on it, I should
have seen that before. The visitor pattern is a bad thing. That's the
position I'll assume based on study and experience, thank you very much.
That is the reason for my comments on the alternate code you
discussed. Passing in the renderer interface implementation allows us
to keep the platform-specific rendering code in a separate class, and
does so in a very literal way. I'd rather not hide all of that behind
a visitor object.
The ONLY thing that I can see that the visitor pattern is good for is
to eliminate the need to change method signatures as things are
changed over time. That is why it (or something like it, not really
such a literal interpretation of it) has been discussed for the
ShoppingCart, especially the constructors for the cart item which tend
to change over time, and are ridiculously large right now (more than
5-6 parameters gets hard to keep track of when you're trying to
remember which is which, and there is nothing like attribute names in
XML to help you out).
3. Convert the existing artifact gathering code to a
screen widget visitor. That would get the artifact gathering
code out of the model widgets and put it where it belongs.
It would probably simplify the artifact gathering code as
well.
I'm not sure what this means... but I might be missing
something obvious. Hopefully someone else has more helpful
comments.
I can't think of a simpler way to explain it. The artifact info
gathering code belongs in the webtools component, not in the model
widget classes. In other words, it's okay for artifact info
gathering classes to know about model widget classes, but model
widget classes shouldn't have to know about artifact info gathering.
I see, the Artifact Info stuff.
Actually, I'd prefer the opposite. IMO things should be as self-
describing and know as much about themselves and things they depend on
as possible. That's something I'd really rather not externalize. In
fact, it would have been really cool if this stuff just used for
artifact info was inherent in the classes, but because things are
looked at differently than how they are when they are actually used it
doesn't quite work that way, or more importantly sometimes it DOES
work that way so it would be a pain to have that separated.
Either way, this stuff certainly doesn't belong in the webtools
webapp. The actual intended use of this code was originally to be data
gathering code for an IDE plugin. So far no one has picked that
project up, and we needed something to test this stuff with (and it is
moderately useful too), so that is why there is a very basic UI for it
in webtools.
-David