Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^8: Why encapsulation matters

by Ovid (Cardinal)
on May 20, 2008 at 06:04 UTC ( [id://687520]=note: print w/replies, xml ) Need Help??


in reply to Re^7: Why encapsulation matters
in thread Make everything an object?

Then I clearly misunderstood you when you said that "encapsulation is king ... is wrong" and I apologize for that. It sounded to me like you were disagreeing with the idea of encapsulation rather than placing it in context. However, I would humbly suggest that such a subtle point is easily lost when you start out by being confrontational. (Though I'm as just as guilty of the negative comments as I can get riled up when I'm poked)

And you still haven't pointed out how my response to the OP was at odds with the first article. I made an example out a common OO mistake of how not encapsulating something (and thus failing to abstract it) could lead to serious bugs. This is a well-known failure mode by having poorly distributed responsibilities. In regards to the first link you had posted: I was writing about poorly distributed responsibilities -- a common problem I would like to solve -- and the author was writing about achieving minimal classes -- a common problem he would like to solve. These ideas are not contradictory.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re^9: Why encapsulation matters
by BrowserUk (Patriarch) on May 20, 2008 at 08:15 UTC
    And you still haven't pointed out how my response to the OP was at odds with the first article.

    The first thing to note is that I never responded directly to your "response to the OP". I responded to his response to it--for counterpoint--and you then responded to me.

    What made my post, and the article it cited, counterpoint to your first post, is this. You suggested that he move the Paper->Issues->Articles->process() loops inside the Paper class, thus effectively reducing the main application to simply instantiating an instance of the Paper class, with all the processing being done as side-effect (calling _initialise()) of that top-level instantiation.

    The benefit you ascribe to this, is that it allows the marking of the issues(), articles(), process() and post_process() methods as private. Therebye increasing encapsulation. But work that through a little.

    Once you've instantiated that $paper object, all the work of the application is done (by _initialise()), so what do you do with it then? Discard it during global destruction.

    Now, besides that the OP himself pointed out one flaw (in the post to which I responded), that of the possibility that he might need to break the processing up into smaller chunks: It may be best to show the user a list of outstanding issues and prompt to select one, rinse and repeat etc.. What's important is that all of an issue's articles are processed together not that all the issues are processed together.. There are also other good reasons for not hiding all those apis.

    The next application that deals with this dataset might need to filter the articles processed by the issue they come from, or the article author, or keywords within the articles. So, where does that fit with your proposal? Rename _initialise() to (say) _process(), and the add another method (say) _filter(), and then pass a parameter to the constructor to allow it to choose whether to call _process() or _filter() in place of the call to _initialise()?

    Go that route and you have another top-level application that is reduced to instantiating a single instance of a class, and then discarding it again. And your class contains two single purpose methods of which only one will ever be called for any given application run.

    And then another for the next application. And another. And another...

    And that's where my stuffing everything inside your objects phrase comes from. Putting application specific code inside the class rather than leaving it at the application level, in order to increase encapsulation, fails. And it is directly to this suggestion:

    Why not have the paper manage this responsibility since it knows everything in needs to know?

    my $paper = Paper->new($cnf_file);

    and in your Paper package:

    sub new { my ( $class, $cnf_file ) = @_; my $self = # construct your object $self->_initiaze; } sub _initialize { for my $issue ($self->_issues){ while (my $article = $issue->_article){ $self->_process($article); } } $self->_post_process; }

    that the article I referenced, speaks. Hence, counterpoint.

    If you can see another way of interpreting those words and snippets, then I'll apologise for having misunderstood you.


    With respect to confrontational. I attempted to paraphrase the opening line of your response to me: The problem I generally have with OO is that most people don't know it and then they get frustrated .... This is because it's not being taught very well ....

    I was more pointed than you for sure. But to whom was the reader meant to infer you to mean, by "most people" and "they" in that opening paragraph? Me? Scott Meyers? The OP?


    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.

      Update: You wrote: With respect to confrontational. I attempted to paraphrase the opening line of your response to me: The problem I generally have with OO is that most people don't know it and then they get frustrated .... This is because it's not being taught very well .....

      I should have made it more clear that I was not referring to you when I said "most people know [00]". That's one of the problems with forums like this: it's so easy to for misunderstandings like this to crop up :(


      If you can see another way of interpreting those words and snippets, then I'll apologise for having misunderstood you.

      When I said that my example does not conflict with Scott Meyers, I was specifically referring to my example to you: the one with ensuring that the authentication object is specifically responsible for throwing an exception to ensure that one cannot forget throwing that exception. Thus, the bits you quote and the bits I was referring to are not the same. Sorry for the confusion.

      As for my original "paper" example, I also explicitly pointed out that I had deliberately made things private but that they may need to be made public later. When I'm first building a class, just exposing everything with little regard for what I'm exposing offers two distinct problems:

      • Once exposed, I cannot easily revisit the interface (I've made a contract)
      • If I expose something that's tightly coupled to something else in my class, I could make it easy to leave the class in an inconsistent state. This should never happen.

      I've some code on the CPAN which I would desperately love to change the interface to, but since it's exposed, I now have a contract and shipping new code would break that contract.

      Inconsistent state is more insidious. Consider this (contrived but not unusual) example:

      my $person = Person->new( fname => 'Bob', lname => 'Smith' ); $person->birthmonth('january'); $person->birthday(13); print $person->age; # boom!

      That's the sort of "exposing the gory details" which I want to avoid and I find that when I'm creating a class, there's an excellent chance that I won't know up front what bits to safely expose. If I'm creating a person object, there's a chance that I'll need to know their age and the above code will break terribly since I don't know the year.

      Some might argue to just use DateTime objects in this example, but since the 'month' and 'day' are not required, calculating drinking age could easily be off by up to a year. Severe legal consequences there.

      Of course, the core of the problem above, aside from exposing things which should not be exposed, is that this code is loosely written in a procedural style. So my argument would be to not expose methods for setting the month and day until and unless you know you really, really need them (and there's a good chance you won't). By forcing the programmer to not expose things until they understand what and why, they minimize the chance for leaving an object in an inconsistent state and thus breaking code unexpectedly. This also has the side effect of promoting a "minimal" class by not accidentally building in functionality that the user doesn't really need -- something that Scott Meyers certainly seems to approve of.

      Cheers,
      Ovid

      New address of my CGI Course.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://687520]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (1)
As of 2024-04-25 04:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found