Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re^6: Why encapsulation matters

by Ovid (Cardinal)
on May 19, 2008 at 13:23 UTC ( [id://687380]=note: print w/replies, xml ) Need Help??


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

Oh, and I forgot to point out the incredible irony of your post: you take me to task for disagreeing with an article that you didn't understand. You wrote:

Re-read my post to which you responded. Follow the links. Re-evaluate your knowledge and experience in the light of the credentials of the author I quoted.

And later you wrote:

The assumption, that encapsulation is king ... is wrong. In so many ways.

You repeatedly argued that I didn't know what I was talking about, but you apparently didn't understand the article you linked to. Just look at the title:

How Non-Member Functions Improve Encapsulation
Scott Meyers
When it comes to encapsulation, sometimes less is more.

When you read closer what he writes, his "less is more" isn't referring to less encapsulation being better. He's arguing that minimal classes give you an opportunity for better encapsulation. He's arguing that "encapsulation is king" and I agree with him even though you have stated that this argument is wrong. What I don't agree with is the assertion that his "one solution" (out of at least six that I previously alluded to) is the only (or best) solution. Your "encapsulation is king ... is wrong" completely misses the point of what the author was arguing for.

Go back and reread what he wrote. Carefully. Go back and reread what I wrote and see how my concrete example does not, in any way shape or form, conflict with what he wrote.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re^7: Why encapsulation matters
by BrowserUk (Patriarch) on May 19, 2008 at 22:49 UTC
    you take me to task for disagreeing with an article that you didn't understand.

    Of course I understood it. Else why would I have made such efforts to emphasis the following (re-quoted with my original emphasis intact):

    If, on the other hand, that function can be implemented as a non-member, non-friend, "free" function (sub) it won't have to change if the data format changes, so doing so increases encapsulation.

    No one, neither he not I, are arguing that encapsulation isn't important. It's all about how you achieve it. My point was and is clear. It is not necessary, or desirable, to stuff everything inside the class in order to achieve encapsulation.

    His point was that encapsulation can be maintained, and even enhanced, by keeping stuff out of the class. Contrast that approach with your "My argument goes like this: expose nothing" approach?

    You also say: He's arguing that "encapsulation is king" and I agree with him ..., but I think we must have read different articles.

    There are four tenants of OO, and if any of them are king, it has to be abstraction. The trick to effective use of OO (remember the key word in the titles of his series of books?), is to balance those four tenants.

    • Inheritance is a useful way of achieving code re-use (DRY), if used correctly.

      But it is well documented that over-use of inheritance leads to a big ball of OO spaghetti (to mix a few metaphors).

    • Polymorphism is another useful mechanism for achieving code re-use, when used correctly.

      But using it incorrectly leads to dichotomies that are unresolvable.

      Eg. Building a Point3D class on top of a Point2D class doesn't work, because a 3D-point is not a specialisation of a 2D-point. Any given 2D point will map to an infinite number of 3D-points from any given observers point of view. And that same 2D-point can be mapped to any single 3D-point, from an infinite number of planes of observation. However, a 2D-point can always be derived from a 3D-point successfully.

    • Encapsulation can yield benefits in reduced maintenance.

      But they nearly always come with an up-front cost in increased development and complexity. Balancing the needs of the (foreseeable) future against the costs of knowable now, is the trickiest decision every architect has to make.

      Done right, encapsulation minimises the costs of change by containing them, thus decreasing coupling. Done wrong--eg. stuffing everything into one big class--it increases coupling, increases the length of dependency chains, and so increases the costs of change.

      The target of encapsulation, its raison d'etre, is to simplify maintenance. Not to hide everything from everyone.

    • Abstraction yields benefits by simplification.

      Files and folders (or directories) are simpler concepts to think about and use than i-nodes, free-space chains and disk-blocks. Arrays are simpler to program than pointers and index register manipulations. CGI forms are easier to use and program than the query strings they hide. Pull-down menus, check-boxes and dialogs are easier to navigate and get right than endless streams of scrolling man pages and huge long strings of nearly meaningless option strings (What do you think the option is to disable spurious warnings of uncheckable memory bounds?).

      But even an abstraction comes with a cost. Simplicity for the user is traded against complexity for the implementor. Again, a balance must be sought.

      But the other three tenants serve only to service the needs of the abstraction. Once sight of that fact is lost, and they start to becomes ends in their own right, the very purpose of OO (simplification through abstraction) is lost also. Thence comes complexity for only the sake of dogma.

    There's a long, wordy, difficult and sometimes very repetitive, but oh so insightful document, Object Orientation Redefined I highly commend to you. It's a difficult but very well worth while read.


    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.

      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.

        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.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-03-29 14:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found