[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: aName
     name := aName

     "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  

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