[Seaside] Smalltalk design advice -
howtoimplement genericbi-directional pointers?
Aaron Rosenzweig
aaron at cocoanutstech.com
Mon Dec 24 14:08:43 UTC 2007
Thank you Ramon for your well thought out explanation. It helps a
lot. Your "Tsunami" package sounds exactly what Sophie and I
*thought* we wanted, but now after gaining your insights, it's
probably not the way to go. Still, it sounds like Tsunami is a great
technical achievement and could be used in other ways in the future.
As an aside, you might want to copy some of your previous reply and
paste it into the general description of Tsunami on SqueakSource so
that the casual passer-by can weigh the pros and cons of the technique.
I have to ask this next question, let's reconsider the code snippet
you offered:
On Dec 24, 2007, at 2:39 AM, Ramon Leon wrote:
> name
> ^name
>
> name: aName
> self testName: aName.
> set doSetName: aName.
>
> testName: aName
> "throw exceptions for business rule violations"
>
> doSetName: aName
> name := aName
I get it. You separate the concerns of "testing" and "setting" into
methods that can be overridden. You also don't want to allow the
general "setter" to save invalid data, so you construct it in a
clever way to call the other two methods. Even though this all makes
sense, it begs a question... "Maybe data validation happens too soon?"
Imagine "name" was bound up to a text field on an HTML web form.
Let's say that the testing code required the first letter of the name
to be in upper case to pass. So I type my last name into the field
like so "rosenzweig" and click "submit". Because an exception gets
thrown, we can imagine that we capture it and will display an error
dialog to the user upon page reload. The error message could be quite
verbose, even blurting out "you typed 'rosenzweig' but should have
typed 'Rosenzweig'". However, the actual "name" value is still nil
and you won't see "rosenzweig" in the text field, you'll see emptiness.
I would offer a slight variation. I would write your snippet like so:
name
^name
name: aName
name := aName
validateName
"Massage _name_ to pass validation if possible, otherwise
throw exceptions for business rule violations. If an
exception is not thrown, set the corrected
(or unmodified) value"
The idea here is that "name" will always get set, regardless of what
is typed, but it might not be saved to your persistence layer (object
database - Magma, or relational database - GLORP). When you type in
"rosenzweig" and hit "submit", one of the following could occur:
1) An exception will be thrown. A descriptive error dialog will
appear on page refresh. The value of "name" will still show
"rosenzweig" in the text field. The user sees what they typed but
realize it didn't validate and can offer a slight modification then
resubmit.
2) The method "validateName" is clever enough to realize that it can
silently coerce (massage) "rosenzweig" into "Rosenzweig" on the
user's behalf. The corrected value gets committed to the persistence
layer and the user is taken to the next page.
This technique hinges on something knowing when and how to call
"validate" methods on attributes. Perhaps the persistence layer will
call "validateForSave" on each object before it actually does a
commit. "validateForSave" would then, in turn, look over all of its
attributes and call the "validateObject" method for each one, if it
is defined.
-- Aaron
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/seaside/attachments/20071224/0add4af4/attachment.htm
More information about the seaside
mailing list