On Sat, Nov 14, 2009 at 2:11 PM, John Harrop <jharrop...@gmail.com> wrote:

> On Sat, Nov 14, 2009 at 11:42 AM, André Thieme <
> splendidl...@googlemail.com> wrote:
>
>> Dereferencing *persons* will result in:
>> {"Tina" #<r...@7ae6d: {:name "Tina", :age 19, :friends []}>,
>>  "Jeff" #<r...@125d92c: {:name "Jeff", :age 22, :friends []}>,
>>  "Karl" #<r...@14fa0ef: {:name "Karl", :age 20, :friends []}>}
>> Great so far.
>>
>> People can become friends, so we need
>> (defn add-friend [#^String person #^String friend]
>>  (dosync
>>    (let [p (get @*persons* person)
>>           f (get @*persons* friend)]
>>    (alter p update-in [:friends] conj f))))
>>
>> So, Tina can get the friends Karl and Jeff:
>> (add-friend "Tina" "Karl")
>> (add-friend "Tina" "Jeff")
>>
>> Now the problem is: *persons* acts as our data base, and
>> when a request comes in (to our web application, hosted by,
>> say, Compojure) we want to see a consistent snapshot of the
>> DB.
>> But derefing *persons* won't do this for us.
>> Even when we deref Tina, we can not be sure who her friends
>> are, as those live in their own refs.
>> They have to. If Karl gets one year older then we only want to
>> change his date, and not traverse all persons first and see if
>> they have Karl as a friend and if yes updating his age there too.
>>
>> How can we handle this situation?
>
>
> I think the design in this sort of case needs changing.
>
> Repeated structure references also pose a problem for storage and retrieval
> (at least if not using a real DB) as Clojure's prn and read will turn shared
> substructures into separate copies.
>
> What's needed here is to make all person lookups go through one point, the
> *persons* table, so the :friends key would store a vector not of person
> struct references but simply of names.
>
> When you start using a real DB this won't change; only the name of the
> concept will, to a "key column". Name will be a key column in the *persons*
> table and will be how you get at particular rows (persons) in the table.
>

Actually, often you have to go further. For example, in the example above,
to accommodate name changes, the name field can't be the key field or you're
back to having to update every reference. There's also the possibility of
duplicate names for two different people; you don't want it to blow up (or
worse, mix two peoples' private data and make it all visible to both) as
soon as your Facebook clone's second John Smith signs up.

In situations like these, a computer-generated id is typically used as an
immutable key field:

table person

id            name             age        friends
000           Karl             20         [002]
001           Jeff             22         [002]
002           Tina             19         [000 001]

(I took the liberty of assuming you actually want friends to be a symmetric
relation, so add-friend will friend each person to the other. If not, it's
still a viable example of using a numeric GUID (globally-unique identifier).
Of course the UI can still display names rather than numbers in most
situations (the URLs generated by your web framework will need URLs -- if
you had http://myfacebookclone.com/profile/john_smith as a URL, which John
Smith? Better http://myfacebookclone.com/profile/1653782 even if it's less
human-understandable. Manually typing in URLs is rare user behavior anyway,
if your page linkage structure is decent).

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to