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/ http://aviewfromafar.net/
On Wed, Oct 1, 2008 at 7:54 AM, Ashley Moran <ashley.moran at patchspace.co.uk> wrote:> 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?It''s been a while since I''ve taken a look at it, but Luke Redpath 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 http://github.com/trotter/belongs_to_demeter. Cheers, David> > Ashley > > -- > http://www.patchspace.co.uk/ > http://aviewfromafar.net/ > > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 1 Oct 2008, at 14:11, David Chelimsky wrote:> It''s been a while since I''ve taken a look at it, but Luke Redpath 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 > http://github.com/trotter/belongs_to_demeter.Cool, thanks for the pointers there! Ashley -- http://www.patchspace.co.uk/ http://aviewfromafar.net/
On Wed, Oct 1, 2008 at 6:11 AM, David Chelimsky <dchelimsky at gmail.com>wrote:> It''s been a while since I''ve taken a look at it, but Luke Redpath 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081001/7af86c3b/attachment.html>
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 Oct 1, 2008, at 7:54 AM, Mark Wilden wrote:> On Wed, Oct 1, 2008 at 6:11 AM, David Chelimsky > <dchelimsky at gmail.com> wrote: > > It''s been a while since I''ve taken a look at it, but Luke Redpath 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. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081001/2ea9c537/attachment.html>
On Wed, Oct 1, 2008 at 11:29 AM, Michael Latta <lattam at mac.com> 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081001/f58aaeb2/attachment-0001.html>
On Oct 01, 2008, at 8:17 pm, Mark Wilden 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/ http://aviewfromafar.net/
On Wed, Oct 1, 2008 at 6:22 PM, Ashley Moran <ashley.moran at patchspace.co.uk>wrote:> > On Oct 01, 2008, at 8:17 pm, Mark Wilden 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. >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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081001/364fcc8a/attachment-0001.html>
On Wed, Oct 1, 2008 at 8:38 PM, Mark Wilden <mark at mwilden.com> wrote:> On Wed, Oct 1, 2008 at 6:22 PM, Ashley Moran <ashley.moran at patchspace.co.uk> > wrote: >> >> On Oct 01, 2008, at 8:17 pm, Mark Wilden 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. > > 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> 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 > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Oct 02, 2008, at 2:38 am, Mark Wilden 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/ http://aviewfromafar.net/
On Wed, Oct 1, 2008 at 7:06 PM, David Chelimsky <dchelimsky at gmail.com>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.> 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 exampleIn 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081002/b8d66710/attachment.html>