Live data from Hacker News

Tell, don't ask

robots.thoughtbot.com

51–60 of 88 posts

Re: Tell, don't ask

#51
post #49

Earlier quoted context omitted.

There's a saying about good OO code, everything happens somewhere else.

It's a slippery slope, though. When you have a chunk of 50 consecutive lines with branches, then yes, that might be worth an abstraction. Sadly too often, in ruby, I see people turning 8 consecutive lines into 4 layers of indirection...

The slope flows the other way IMHO, most of the time most programs I've seen arent abstracting enough and the code is far to sequential and unnecessarily complicated because of it. Excessive if and switches seem far more common to me than excessive use of polymorphism.

Re: Tell, don't ask

#52
post #38
post #17

Earlier quoted context omitted.

I first heard "Tell don't ask" in relation to Smalltalk. If you want a developed vocabulary, Smalltalk is where you find it (and it's been there for thirty-odd years).

What would you recommend? Smalltalk or Pharo?

Pharo is a Smalltalk, and yes, Pharo.

Re: Tell, don't ask

#53
post #49

Earlier quoted context omitted.

It's a slippery slope, though. When you have a chunk of 50 consecutive lines with branches, then yes, that might be worth an abstraction. Sadly too often, in ruby, I see people turning 8 consecutive lines into 4 layers of indirection...

The slope flows the other way IMHO, most of the time most programs I've seen arent abstracting enough and the code is far to sequential and unnecessarily complicated because of it. Excessive if and switches seem far more common to me than excessive use of polymorphism.

Two sides of the same coin. Your example is newbie programmers, mine is the same newbies on their second project. ;)

As usual it's all about striking the balance. I wonder if one day we'll come up with a programming language that can enforce these things in a meaningful way.

Re: Tell, don't ask

#54

Example 3 adds a nonsense method, EmailUser#send_to_feed. What does that mean? Email users don't have feeds. If we're going to evangelize OO purity, let's do it right. class Post def created user.post_created(self) end def send_to_feed(feed) feed.send(contents) end end class TwitterUser def post_created(post) post.send_to_feed(twitter) end end class EmailUser def post_created(post) # no-op. end end The post merely te…

This is all nonsense anyway. There's no such thing as a TwitterUser or an EmailUser. You just have users, some of whom use Twitter, some use email (and may have multiple addresses), and some use both, and they can edit their settings to add and remove accounts and change notification preferences. So it's really has-a rather than is-a. Adding unnecessary inheritance is far worse than the original problem.

I completely agree with you. I actually find the 'cleaner version' much much harder to read.

Every time I look at the code I have to 'recompile' it in my brain, just because it's doing such a simple thing in such a darn complex way.

Re: Tell, don't ask

#55

This has long been one of my favorite methods of using OO code to my advantage; and is one of the main reasons that my code is OO in the first place. There are many cases where it's easier/lazier to have if-statements. Going further, you can take the things learned in this article to make your general purpose code potentially faster, as well. For example, if a set of things that must be performed in order; and someti…

I'm not clear on how that makes your code more maintainable though. The first case makes it explicit that any of the actions can fail to occur, whereas the second one, on first glance, seems to have all the actions occuring. I, as a newcomer to this code, will almost definitely make that mistake, which will make debugging or maintenance harder.

The only way the second is even -as good- is if I'm constantly holding in my mind the various idioms you've used in the code, in this case that your function pointers are never null but will instead refer to an action that might do nothing. As far as I can tell, this is more work for me, for no gain.

I would love to hear your reasoning why this way of doing it is -better-, as opposed to just -more object oriented- (or -marginally less typing-).

Re: Tell, don't ask

#56
post #53

Earlier quoted context omitted.

The slope flows the other way IMHO, most of the time most programs I've seen arent abstracting enough and the code is far to sequential and unnecessarily complicated because of it. Excessive if and switches seem far more common to me than excessive use of polymorphism.

Two sides of the same coin. Your example is newbie programmers, mine is the same newbies on their second project. ;) As usual it's all about striking the balance. I wonder if one day we'll come up with a programming language that can enforce these things in a meaningful way.

My example is not newbie programmers, rather, much code written by experienced OO programmers who don't have a Smalltalk background. I can't say what it looks like now, but I recall Rails active record implementation being heavily procedural in nature when I first looked at it way back and DHH is hardly a newbie. Decompile most classes in the dot net framework, and you'll find a fuck ton of procedural code even though it presents an OO API. 500 line methods are not uncommon.

When you learn OO in a procedural language like ruby or java, you tend to have a slightly odd idea of OO. Just because a language supports objects doesn't make it object oriented, it just allows object orientation.

I thought I knew OO until I learned Smalltalk, and discovered just how deep the rabbit hole can go. If's, foreach, while, unless, switches, these are all procedural constructs. You don't truly grok OO if you can't write a program without using procedural constructs (as an exercise).

And who knows, maybe someone will invent a language that nails the balance, I won't bet on it soon though.

Re: Tell, don't ask

#57

This has long been one of my favorite methods of using OO code to my advantage; and is one of the main reasons that my code is OO in the first place. There are many cases where it's easier/lazier to have if-statements. Going further, you can take the things learned in this article to make your general purpose code potentially faster, as well. For example, if a set of things that must be performed in order; and someti…

I'm not clear on how that makes your code more maintainable though. The first case makes it explicit that any of the actions can fail to occur, whereas the second one, on first glance, seems to have all the actions occuring. I, as a newcomer to this code, will almost definitely make that mistake, which will make debugging or maintenance harder. The only way the second is even -as good- is if I'm constantly holding in…

I may expand on this later; but, whenever you're going to a new code-base, you're going to have to learn the various idioms that are at work in that code base. This is especially true when you're working with some more complicated languages where no one uses the whole set of it (see: C++).

When I'm writing my code, I personally find that being able to trust what my code is doing to be more readable. In the case I wrote above, more than likely, I would have arrived at that point by first writing whatever the first action was; and then coming to know that there could be two different actions that could have taken place (causing a method call/inheritance to occur) and then I realized that sometimes, nothing might happen. Now we have a nothing case. The nothing case did not negatively effect my code flow. I am not 100% sure I would write code like I had above in the first place, it would grow to that state organically; but, the advantage of trust later on, was worth noting.

I originally heard this concept a long, long, long time ago; and one of the interesting selling points that the person that told me it was that code could be faster run if it had no if-statements, reason being branching and branch prediction forces the processor to rewind; whereas a guaranteed jump is potentially less expensive, especially if the code is in the cache. Of course, this would be a premature optimization, but if the code occurred in the inner-most loop, there may be some gains to be had that otherwise wouldn't be.

I suppose, for me, it looks cleaner when you're dealing with larger projects. That said, as I contemplate it further, I could certainly see where it would slip up some people, especially newcomers to my code. This sort of creativity would probably primarily spring up in organic/fluid code where OO paradigms are already in place.

Thanks for making me think on this further :)

Re: Tell, don't ask

#58
post #53

Earlier quoted context omitted.

Two sides of the same coin. Your example is newbie programmers, mine is the same newbies on their second project. ;) As usual it's all about striking the balance. I wonder if one day we'll come up with a programming language that can enforce these things in a meaningful way.

My example is not newbie programmers, rather, much code written by experienced OO programmers who don't have a Smalltalk background. I can't say what it looks like now, but I recall Rails active record implementation being heavily procedural in nature when I first looked at it way back and DHH is hardly a newbie. Decompile most classes in the dot net framework, and you'll find a fuck ton of procedural code even thoug…

Well, this is leading a bit astray.

In principle I agree with you, but in general procedural constructs are not harmful and should be used where appropriate.

500 lines is indeed a bit much, but I've seen through 100 line methods without an urge to refactor.

The best programs are those that have both; good use of patterns and the odd suspiciously long method if appropriate.

The worst programs are not only the classic spaghettis but also those that dogmatically stick to a pattern even where it makes no sense. Java is notorious for the latter, but I also often see ruby programs where the author religiously clinges to the belief that no method can be allowed to exceed 5 lines of code. That, in combination with misunderstood unit-testing (foo.MUST_RECEIVE :bar), often leads to ridiculously tight coupling and effectively a monolithic brick that is resilient to change.

I call these programs Gnocchi-code. A close relative of spaghetti, just higher density...

Re: Tell, don't ask

#59
post #53

Earlier quoted context omitted.

Two sides of the same coin. Your example is newbie programmers, mine is the same newbies on their second project. ;) As usual it's all about striking the balance. I wonder if one day we'll come up with a programming language that can enforce these things in a meaningful way.

My example is not newbie programmers, rather, much code written by experienced OO programmers who don't have a Smalltalk background. I can't say what it looks like now, but I recall Rails active record implementation being heavily procedural in nature when I first looked at it way back and DHH is hardly a newbie. Decompile most classes in the dot net framework, and you'll find a fuck ton of procedural code even thoug…

excellent explanation of OO. thanks.

Re: Tell, don't ask

#60
post #53

Earlier quoted context omitted.

Two sides of the same coin. Your example is newbie programmers, mine is the same newbies on their second project. ;) As usual it's all about striking the balance. I wonder if one day we'll come up with a programming language that can enforce these things in a meaningful way.

My example is not newbie programmers, rather, much code written by experienced OO programmers who don't have a Smalltalk background. I can't say what it looks like now, but I recall Rails active record implementation being heavily procedural in nature when I first looked at it way back and DHH is hardly a newbie. Decompile most classes in the dot net framework, and you'll find a fuck ton of procedural code even thoug…

What's so "procedural" about 500 line routines (procedures, methods, functions)?

That's just crappy coding in any language. And I see it all too often, alas.

Having missed out on Smalltalk back in the 80s, I will venture to ask how one does conditional execution or terminates recursion without an "if", though? Even Lisp has its "(COND ...)" expression (yes, I know that's not OOP).

Post reply on HN