Hi Jon,

> Dan,
> I hope I didn't ignite some negative reactions.  Not my intentions.

Is this in reply to my message?  It looks like you addressed this
reply to me, but replied to David's?

> There are certainly parts of the DM API which are not consistent but
> that's why its not v1.0 yet, right?

Yeah, that's why we've held off 1.0 despite alot of pressure to go
1.0.  As soon as we do, there's API lock-in and it will be alot more
difficult to make changes.  Even now though there's a certain amount
of lock-in due to the size of the community that we have to work
around each time there's a change. For every change there needs to be
a deprecation period lasting at least a few months where the old and
new approach works, as well as updated specs, docs and dm-more
plugins.

I think one of my points in my grandparent post was that IMHO being
consistent in an API is more important to me than convenience.  I like
things that are consistent to use, and consistent internally.  If one
is at odds with the other I personally opt for consistency when
designing APIs.

I think that's why most people are attracted to DataMapper too -- they
prefer the explicitness of the property and relationship declarations,
and how easy it is to understand the structure of DataMapper models
due to their consistency.  And while we could introspect the structure
from the data store to define the properties, we decided that trading
off a bit of convenience for something that is easier to understand at
a glance.

> I'm ok with that as long as others are ok with continuing the debate
> on making it more so untl we get to a 1.0 API

If we're doing something totally at odds with established conventions
in data modeling I would like to discuss it.  However, I'll provide
the reasoning behind the way has() works the way it does, and give a
sneak peek into a future planned API that may actually solve some of
the usability issues.

> I'm working more on my code tonight.  I'll think about your comments
> and see if I can make a better reply

There was a time when I first used AR about 3 years ago that has_one
and belongs_to was confusing.  I would always forget which side of the
relationship the key was on with has_one, since I rarely use it.  It
wasn't until I started working on DM earlier this year that it made
sense.

In DataMapper the has() keyword implies ownership of the model on the
other end of the relationship.  We decided to use the term parent/
child to describe the two sides, after discussing it at length because
we couldn't think of anything better. The commands has(n), has(n..n),
has(1), and has(0..1) are all used on the parent model, and alter the
child model to have a child key (FK) that points back to the parent.

In data modeling, at the conceptual level, the entities on either side
of a one to one relationship are equal.  The term "has one" is correct
to describe the relationship each entity has to the other.  It's only
when you attempt to describe the relationship at the physical level
that you have to decide which of the entities is going to receive the
foreign key.  In all the data modeling reference material I could
find, it was stated that the FK should be placed on the entity where
the "must be one of this for the other" constraint is more likely to
be relaxed.

A poor example of this (but the best I can think at this time) is
imagine you have a Part and a Bin, where "Part has one Bin", and "Bin
has one Part". Say that it doesn't make as much sense to store
multiple Parts in a Bin, and you can conceive that someday you might
have so many Parts than could fit in a single Bin.  Given this you
place the FK on the Bin side, which would allow you at some point to
relax the application logic and the "Part has one Bin" constraint can
become "Part has many Bins".  In DM this would mean you change the has
(1) constraint to has(n) and nothing changes at the schema level.

I'll concede that the choice to put the FK at the "other end" when
using has(1) is totally arbitrary on DM's part. The main reason it was
done was to maintain consistency with other has() usages.

IMHO belongs_to is a bit ugly, and a hold-over from AR.  The term
"belongs to" is clumsy in alot of cases, and I think causes
confusion.  Sure, it makes sense to have Order belongs_to Customer.
But there are many other cases where this doesn't read too clearly.
One option would be to have a few aliases that mean the same thing at
belongs_to, but that sort of breaks with consistency and increase the
size of the API that one would have to learn before being able to read
a DM model.

The option that I am leaning towards right now is to deprecate
belongs_to and make it so you can define a property() that references
the other model.  So instead of this:

  class Order
    # ...

    belongs_to :customer
  end

You could write:

  class Order
    # ...

    property :customer, Customer
  end

So the usage of a Model as the property type would create the customer
accessor/mutator (which is exactly what happens anyway for a type),
but it would also create whatever child keys you need underneath.  Any
options passed to property() would be passed down to the child keys on
creation, allowing you to specify nullability, indexes, etc.  I think
this reads quite naturally, and so far everyone I've shown it to
thinks it is pretty easy to understand.

This also fits in nicely with the planned Embedded Value type (see
PoEAA).  It would use the same API as a Model, so that the DM model
user would only see that there was a "customer" property, which could
map to an Embedded Value.  Later it could be upgraded to a full Model
by changing the "include DataMapper::EmbeddedValue" line to "include
DataMapper::Resource", and of course a classic migration to move the
data over.

The only barrier to this is that we have to figure out a strategy to
handle cases where the Customer model hasn't been loaded yet.  Since
model load order is nondeterministic this is a very real possibility.
Unless it is dealt with an exception could be thrown because the
Customer constant hasn't been defined.  I think I have a solution
using const_missing in DM::Model, but I want to make sure it will work
properly with threading and a few other scenarios.

Dan
(dkubb)
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"DataMapper" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/datamapper?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to