On Fri, 10 May 2013, Robert Kern wrote:

On 2013-05-10 12:00, Steven D'Aprano wrote:

But either way, that's fine. You've found an object where it does make
sense to have an explicit "make it go" method: first one entity has
permission to construct the object, but not to open the underlying file.
Another entity has permission to open the underlying file, but not to
create the object. I have no idea whether this is a reasonable security
design or not, it actually sounds a bit rubbish to me but what do I know?
So let's treat it as a reasonable design.

As I've said, repeatedly, that's not what I'm talking about.

When you DON'T have useful things that can be done with the object before
calling "enable", then it is an anti-pattern to require a separate call
to "enable" method, and the enable functionality should be moved into the
object constructor. If you DO have useful things that can be done, like
pass the object to another entity, for security, then that's a whole
'nuther story.

I'd be curious to see in-the-wild instances of the anti-pattern that you are talking about, then. I think everyone agrees that entirely unmotivated "enable" methods should be avoided, but I have my doubts that they come up very often. Do programmers have a natural tendency to make an extra, completely unnecessary method? I would think that they have a natural tendency to the opposite.

In my experience, everyone has a reason in mind when they follow a pattern/anti-pattern. It is pretty rare that someone just does some specific, nameable thing for no reason at all. There is no need to call out an anti-pattern for which no one has a reason to do it. But there is a continuum of reasons. Some reasons are better than others. Some reasons only apply in a small set of circumstances but seem like they would apply more generally, at least to novice programmers. Programmers can be wrong about what they think the (anti-)pattern actually achieves. The whole point of naming an anti-pattern is to discuss those reasons, show where they are misapplied, where YAGNI, why novices overuse it, other patterns that should be used instead, and also the circumstances where it is actually a good pattern instead.

I'll share the anti-pattern that I've seen many times (not actually in Python)

    class CoolPresenter:
        def __init__(self):
            self.view = None
            self.some_property = None
            self.other_property = None

        def initialize(self):
            self.view.disable()
            data = self.load_data()
            self.view.data = data
            self.view.enable()


        def reload(self):
            if self.view is None:
                raise NotInitializedError("Error: Please setup class")
            self.view.disable()
            data = self.load_data()
            self.view.data = data
            self.view.enable()



Then you would see code like this:

    presenter = CoolPresenter()
    presenter.view = CoolView()

This is just plain silly for a few reasons:

    - It's ambiguous. I don't know what's required for the CoolPresenter
      to function properly.

    - The temporal coupling mentioned earlier. I can create an instance of
      a class and then call a function (say `reload`) and then boom! My
      program crashes. There is *no possible* use case of this class where
      you can use it without a view.


The motivation behind this anti-pattern that I've seen is the desire to not have a constructor that "does too much". So you end out with an empty constructor and temporal coupling, and a terrible API that doesn't clearly explain the requirements of the class. Your class constructor should *require* everything that is necessary to have a stable state when the class is created (i.e. you should be able to properly call any function, set any property without an exception happening)

Why? Less bugs, easier to comprehend, change/update your code. Easier to use the class.

-W
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to