Associations should be private

Hi

The discussion among me, David, Michael, and Pat got me thinking.
Specifically this by Michael:

Just my $0.02, but I really like specs to be treated as
specifications for what SHOULD be happening, not pretending other
code is different than it is.

This made me think the real solution is for ActiveRecord/A N Other ORM
to declare that its associations are proxies and not arrays. But
that’s terrible, because it’s encouraging users to manipulate the
ORM objects’ structures.

So what if you flatly make all associations private? Is this a good
idea? Has anyone tried it?

Ashley


http://www.patchspace.co.uk/

On Wed, Oct 1, 2008 at 7:54 AM, Ashley M.
[email protected] wrote:

terrible, because it’s encouraging users to manipulate the ORM objects’
structures.

So what if you flatly make all associations private? Is this a good idea?
Has anyone tried it?

It’s been a while since I’ve taken a look at it, but Luke R. has
a plugin called Demeter’s Revenge
(http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk)
that actually manages this all for you by adding methods like
team.add_player that wrap chains like team.players.add. It’s a year
old and I don’t know if it works w/ the latest rails updates or not.

I think that if you’re actually writing a bunch of boilerplate code
the same way over and over without a plugin like that, then it’s
probably painful. With something like that it’s painless and
expressive and seriously cleans up your controller code examples.

Glancing at github, I see one other library up there that tries to
solve the same problem. Will have to look closer later at
GitHub - trotter/belongs_to_demeter: Rails plugin to allow access to belongs_to association attributes through methods on the base class..

Cheers,
David

On 1 Oct 2008, at 14:11, David C. wrote:

expressive and seriously cleans up your controller code examples.

Glancing at github, I see one other library up there that tries to
solve the same problem. Will have to look closer later at
GitHub - trotter/belongs_to_demeter: Rails plugin to allow access to belongs_to association attributes through methods on the base class..

Cool, thanks for the pointers there!

Ashley


http://www.patchspace.co.uk/

The point is to never assume the structure of another object, but to
let it decide that. So you never get A.B.C you always use a method on
A to do the work. You get a lot more methods on A but the structure
underneath can change without a ripple effect. For example if you had
2 associations that got merged into one you can still support the same
method interface and then filter the one association to appear to be
2. Or you can merge 2 into what appears to be one, etc. Using
plugins that do this too simply removes some of the value. If they
always map the underlying structure you have not gained much. But, if
you can specify the intended interface and then map that to the
underlying structure you have gained much more. That of course
requires a more sophisticated (complex) plug-in and some added work to
explicitly define the interface. The whole convention over
configuration means that the underlying structure tends to be exposed
more than good software engineering practice would advise, but it
works because most of the time the cost to fix a change is actually
lower in Ruby than the cost of preventing the change.

Michael

On Wed, Oct 1, 2008 at 6:11 AM, David C.
[email protected]wrote:

It’s been a while since I’ve taken a look at it, but Luke R. has
a plugin called Demeter’s Revenge
(http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk)
that actually manages this all for you by adding methods like
team.add_player that wrap chains like team.players.add. It’s a year
old and I don’t know if it works w/ the latest rails updates or not.

See, this is what I don’t get about Demeter. By adding delegators, you
might
trick someone into thinking that you’re not playing with other objects’
parts, but really you still are. Does Demeter just mean mechanically
adding
a level of indirection?

For example, in the case under discussion, even with Demetering, you’re
still going to get back a proxy object, and end up with the same
problem,
aren’t you?

///ark

P.S. Of course, controlling access to data (especially changing it) can
often be a Good Thing. But that’s just a general principle and applies
to
your own data as well as to your data’s data’s data. Nothing Demetery
there.

On Wed, Oct 1, 2008 at 11:29 AM, Michael L. [email protected] wrote:

The point is to never assume the structure of another object, but to let it
decide that. So you never get A.B.C you always use a method on A to do the
work. You get a lot more methods on A but the structure underneath can
change without a ripple effect.

Sounds like future-proofing to me. In the case of libraries, that can be
a
good thing. For application code, it flies in the face of YAGNI.

Using plugins that do this too simply removes some of the value. If
they

always map the underlying structure you have not gained much.

Yes, it was the “auto-demetering” that I was mainly responding to.

The whole convention over configuration means that the underlying
structure

tends to be exposed more than good software engineering practice would
advise, but it works because most of the time the cost to fix a change is
actually lower in Ruby than the cost of preventing the change.

“Embrace change” - Kent Beck. The whole white book is predicated on what
you
just pointed out about Rails.

But here I go again, off the RSpec track…

///ark

On Oct 01, 2008, at 8:17 pm, Mark W. wrote:

Sounds like future-proofing to me. In the case of libraries, that
can be a good thing. For application code, it flies in the face of
YAGNI.

Actually I don’t think that’s a YAGNI. You need an interface to
your models, the question is whether to build one that litters
trainwrecks through your code, or one that is internally refactorable.

Or, you could “take the first Demeter bullet” and use associations
until they cause a breakage…

The whole convention over configuration means that the underlying
structure tends to be exposed more than good software engineering
practice would advise, but it works because most of the time the
cost to fix a change is actually lower in Ruby than the cost of
preventing the change.

… which takes advantage of this property of Ruby.

“Embrace change” - Kent Beck. The whole white book is predicated on
what you just pointed out about Rails.

You meant to say Ruby there, right? ;o)

Ashley


http://www.patchspace.co.uk/

On Oct 02, 2008, at 2:38 am, Mark W. wrote:

However, I say that there are too many things that need doing right
now - right this second - to waste time on what may or may not
happen in the future. Put another way, what are you willing to give
up in order to add this layer?

Perhaps I was a bit terse (and opaque) with the comment "take the
first. What I meant was that, yes, I see your point, and it’s fine to
do it this way if it’s a risk you’re willing to take. But if it
causes you problems, you should always fix the software, not
constantly refactor associations.

Ashley


http://www.patchspace.co.uk/

On Wed, Oct 1, 2008 at 6:22 PM, Ashley M.
[email protected]wrote:

ActiveRecord already provides an interface to your models. If you add on
to
that because it might things easier in the future, that’s where I call
“YAGNI.” It reminds me of a book on Java by a well-known author which
said
that you should declare an interface for every class, because it will
make
things easier if you need to change the implementation. He’s absolutely
right, of course.

However, I say that there are too many things that need doing right now

right this second - to waste time on what may or may not happen in the
future. Put another way, what are you willing to give up in order to add
this layer?

“Litters trainwrecks,” BTW, I believe begs the question.

Embrace change" - Kent Beck. The whole white book is predicated on what you

just pointed out about Rails.

You meant to say Ruby there, right? ;o)

I was responding to the “convention over configuration” remark. But
yeah,
Ruby certainly does make changing stuff easier than many other
languages.

///ark

On Wed, Oct 1, 2008 at 7:06 PM, David C.
[email protected]wrote:

Au contraire! You’re comparing apples and cadillacs here. Demeter is
about encapsulation. Interfaces are about abstraction and structure.
Completely different animals.

Interfaces in that Java book and LOD in this topic were being supported
by
arguments of the form “if you need to change things in the future…”
There
are some practitioners for whom that’s a valid argument, and there are
others for whom it’s an anti-argument. YAGNI is the latter. Doesn’t make
it
right, but it does provide a way to evaluate each of these animals.

dog = dogs[0]

So when the design seems to want to categorize animals into domestic
and wild, the first call has to be changed to
trainer.animals.domestic.dogs.first. Good luck tracking down the
second example

In a statically-typed language, this would be trivial. In a
dynamically-typed language using BDD, this would be caught by tests.

Principles/guidelines like YAGNI and DRY and even the
ever-threatening-sounding Law of Demeter are NOT LAWS. They are
indicators. Red flag triggers. Red flags are warnings, not errors.

We agree on that. See my recent post:
http://www.nabble.com/Prepare-for-newbie-ness-to19516110.html#a19542377

In this case, we’ve got two of these in direct conflict with each

other, so which one wins? Gotta look at the costs and benefits of each
and proceed wisely and in context

I feel that YAGNI and LOD are at different levels of granularity. I use
YAGNI and TSTTCPW in my daily life (which isn’t to say that I always
think
they’re the best approach). So I approach problems using those
principles as
my base. I don’t ask myself a hundred times a day whether I should use a
goto statement - I use structured programming as my base. Same with OOP,
readable code, lack of commenting, etc. You can’t approach everything de
novo. So I apply YAGNI unless I see a compelling reason not to. The
reason
is that the “costs and benefits” of any approach are usually not obvious

especially when talking about the future.

///ark

On Wed, Oct 1, 2008 at 8:38 PM, Mark W. [email protected] wrote:

through your code, or one that is internally refactorable.

ActiveRecord already provides an interface to your models. If you add on to
that because it might things easier in the future, that’s where I call
“YAGNI.” It reminds me of a book on Java by a well-known author which said
that you should declare an interface for every class, because it will make
things easier if you need to change the implementation. He’s absolutely
right, of course.

Au contraire! You’re comparing apples and cadillacs here. Demeter is
about encapsulation. Interfaces are about abstraction and structure.
Completely different animals.

Unless you’re developing an library that will be directly consumed
outside your team, the cost of not adding the Java Interface until the
need for an abstraction arises is very low. Finding all of the
instantiations of the class is easy, and converting them to us a
factory call is easy too.

Tracking down all of the trainwrecks in a system is not quite so
simple. First of all, they are not guaranteed to look the same:

trainer.animals.dogs.first

vs

t = trainer
a = trainer.animals
d = trainer.dogs
dog = dogs[0]

So when the design seems to want to categorize animals into domestic
and wild, the first call has to be changed to
trainer.animals.domestic.dogs.first. Good luck tracking down the
second example.

Principles/guidelines like YAGNI and DRY and even the
ever-threatening-sounding Law of Demeter are NOT LAWS. They are
indicators. Red flag triggers. Red flags are warnings, not errors.

In this case, we’ve got two of these in direct conflict with each
other, so which one wins? Gotta look at the costs and benefits of each
and proceed wisely and in context, not with a face stained with
kool-aide.

FWIW,
David