[Seaside] How do you handle constraints on persisted collections?

Pat Maddox pat.maddox at gmail.com
Wed May 20 07:44:25 UTC 2009


On Mon, May 18, 2009 at 10:49 PM, Ramon Leon <ramon.leon at allresnet.com> wrote:
> Anyway, my approach to your particular issue would be to simply make the
> name field immutable after being set the first time.  A simple guard clause
> in the accessor that threw an exception if someone tried to set the field if
> it already had a value and the new value was different would protect any
> unintended aliasing bugs.  After all, an object should encapsulate its own
> business rules and if the field were unique I'd have modeled that by hashing
> it in a dictionary by that fields value.  It's not the rigorous guarantee
> that a constraint on a set is, but objects aren't about sets, they're about
> instances and in any real program it's pragmatic enough to get the job done.

This got me going in the right direction. Here's what I did:

User>>username: is set-once, for initialization (raises an error if
you call it a second time)
UserRepository changeUsername: fromName to: toName
  | user |
  self ensureUsernameIsAvailable: toName.
  user := users at: fromName.
  users at: toName put: user.
  user replenishUsername: toName.
  users at: fromName put: nil.

This lets me create a user and add it to the repo.  Any changes to the
username have to go through the repo, where it can do its validity
checking.  I put replenishUsername in the repository protocol to make
it clear that it was meant for use by the repository.  At first I had
named the method hydrateUsername but that felt too ORMy to me, I
wanted something more organic sounding since it's pure objects :)

When I needed to add a constraint that a given email address appear in
the list only once, I created a UserProfile object that holds the
username and email.  UserProfile is fully immutable this time,
User>>profile: is write-once and User has a replenishProfile method.
UserRepository now has changeUsername:to: and changeEmail:to: that
find the profile, create a new profile with the given username/email
and existing info, and then updates the user with replenishProfile.

Simple code that I feel is cleanly separated, and will be easy to
change should the requirements get more complex.

Thank you for the feedback everyone, it was very helpful.  I'm curious
to hear any thoughts on my current solution.

Pat


More information about the seaside mailing list