object.enable() anti-pattern

Wayne Werner wayne at waynewerner.com
Sun May 12 12:48:58 EDT 2013


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



More information about the Python-list mailing list