in reply to Re^4: Moose: I want builder method to run every time I call an attribute (ugh)
in thread Moose: I want builder method to run every time I call an attribute

chromatic's suggestion was the example of good OO design.

I've talked about this to significant lengths. But I'll let those interested do the searching (it isn't hard) if they want more than the below rehash.

The original question was an example of how Moose's emphasis on object attributes (with the emphasis on method generation, constructor generation, emphasis away from non-accessor use of attributes from within methods, etc.) just further encourages a problematic focus on class design as "select what attributes you want to store in your objects and which of those you want to have accessors for vs. which you just want transparently exposed via constructor arguments".

IME, good OO design comes from first deciding on the methods you want your class to provide and only after that deciding on the attributes that you want to use in order to implement those methods and keeping the attributes as internal aspects of the design that are not directly exposed in the interface. But it took years for me to recognize the pattern of class designs eventually going further and further wrong and distilling out that this was an important common element of many of these problematic designs.

Objects as "bags of attributes" encourages designs that end up leaking/forcing object behavior into the code that uses the objects like this trivial example:

$obj->log() if $obj->should_log();

The original question shows a person so focused on "what accessors to what attributes should I design into my class?" that they didn't even recognize when they had a simple use-case for a simple, vanilla method (the very thing that should be the focus of the design). So they had to conceive of that as "an accessor but that invokes a builder".

Of course, people often deride "blame the tool". It isn't like Moose forces you to design classes badly. But I couldn't resist when I saw somebody who didn't even recognize the need for "just a method".

The second bad example is using "around" code. Not wanting to misquote, I found a prior summary I wrote that I think sums it up nicely so I'll just repeat it, slightly modified:

So you end up defining a "data type" for that attribute and/or you declare a 'before' or 'after' wrapper around the method.

This leads to: "Your logic for a single class will be split apart into tons of tiny pieces where the order and interactions will become almost impossible to see, predict, adjust, and debug. But your code will look pretty. Just don't try to understand it on any sort of deep level (such as when you need to fix something)."

To which stvn, Moose's creator, noted: "Nothing about Moose forces you into doing something as idiotic as you describe."

I prefer to not write idiotic code. I prefer to not come close to writing idiotic code. So I won't be using even one "around" method. The idea of an "around method" just doesn't even make sense in my classes. You can see the code. If you need to add code, you add it where it needs to go and the flow is obvious. And if you later realize that the order of things matters and is wrong, then you fix that by moving lines of code up or down within a subroutine.

- tye        

  • Comment on Re^5: Moose: I want builder method to run every time I call an attribute (rehash)
  • Download Code

Replies are listed 'Best First'.
Re^6: Moose: I want builder method to run every time I call an attribute (rehash)
by davido (Cardinal) on Sep 27, 2013 at 06:23 UTC

    This is golden.

    My first thought when I saw the question was, "Has Moose made use forget how to write a method? It generally starts with some variation on, 'sub methodname { my $self = shift; ... }'."

    A famous aphorism of David Wheeler goes: "All problems in computer science can be solved by another level of indirection"; this is often deliberately mis-quoted with "abstraction layer" substituted for "level of indirection". Kevlin Henney's corollary to this is, "...except for the problem of too many layers of indirection."

    Humorous Internet memorandum RFC 1925 insists that:

    • (6) It is easier to move a problem around (for example, by moving the problem to a different part of the overall network architecture) than it is to solve it.
    • (6a) (corollary). It is always possible to add another level of indirection.

    (From http://en.wikipedia.org/wiki/Indirection.)

    All these layers of abstraction can become a shell game. Eventually someone's got to actually write some code. Spaghetti code can be written without ever using goto. ;)


    Dave

      Spaghetti code can be written without ever using goto.

      See also OO-tagliatelle :)


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re^6: Moose: I want builder method to run every time I call an attribute (rehash)
by italdesign (Novice) on Sep 27, 2013 at 14:14 UTC
    Thanks everyone. I guess I got a little carried away with Moose's fancy features. ;-) Making it a method makes perfect sense. It seems to me the deciding factor on when to make something an attribute with a builder vs a method is, if the value will remain static throughout the life of the object, and you access it a lot, then attribute is more efficient. Else method.