advice about `correct' use of decorator

Ricardo Aráoz ricaraoz at gmail.com
Mon Sep 3 06:28:45 EDT 2007


Gabriel Genellina wrote:
> En Wed, 29 Aug 2007 07:32:21 -0300, BJörn Lindqvist <bjourne at gmail.com>  
> escribi�:
> 
>> On 8/24/07, Gabriel Genellina <gagsl-py2 at yahoo.com.ar> wrote:
>>> En Thu, 23 Aug 2007 09:20:21 -0300, BJörn Lindqvist <bjourne at gmail.com>
>>> escribi�:
>>>
>>>> def check_user_logged_in(func):
>>>>     def f(*args, **kwargs):
>>>>         if global_state.the_user.is_logged_in:
>>>>             return func(*args, **kwargs)
>>>>         return show_login_page()
>>>>     return f
>>> I think there is a semantic problem, perhaps we are not talking
>>> about the same thing. I'm considering the software complexity AS
>>> PERCEIVED BY THE PROGRAMMER, looking at the interactions between a
>>> program and a programmer who is working on some task; some people
>>> would say "cognitive complexity" to make it clear.
>> There is no semantic problem. You are just mistaken in your belief
>> that the complexity that the user of the decorator has to deal with is
>> different from the complexity in implementing the decorator.
> 
> But they ARE different. That's the whole point of abstractions, code  
> reuse, layered design... Designing a simple interfase on top of a complex  
> system is very common. Nobody writes X-Window code, as nobody writes a raw  
> event loop for Windows anymore: there are very good GUI toolkits, even  
> portable frameworks, that put an abstract layer on top of that so the  
> programmer has a much simple and coherent view. The complexity is behind  
> the scenes.
> 
>>> Which API is more complex: one in which you can play a movie with
>>> just a single call like PlayMovie(Title), or one on which you must
>>> call a zillion functions to firtly initialize the stream format,
>>> configure the display, disable undesired user interfase elements,
>>> locate the movie file, load it in chunks, etc.? The first one is
>>> certainly much simpler to use (simpler = less complex), and maybe
>>> internally it calls the same functions as the second one, but nobody
>>> cares.
>> "nobody cares" is your guess. I'd bet that the caller of the PlayMovie
>> function cares a lot: Is the movie played full screened? Which
>> encodings are supported? Can you set the title of the movie window? Is
>> streaming supported? Does it even work on windows? Which URI schemes
>> does it support?  And so on and so on.
>>
>> That is why no video decoding API:s have a PlayMovie(Title) function
>> and why I haven't seen a single 3d engine with a
>> MakeReallyCoolDoomCloneFPSGame() function.
> 
> (yet!). What about urlopen? Using a single call one can be authenticated  
> and retrieve any file in the other side of the planet. I consider it a  
> simple interfase, altough it does complex things. Would you say it is  
> better to use plain sockets everywhere? Or, since sockets are abstractions  
> themselves, would you say it is better to use lower level primitives  
> instead? Each time you descend a level, you have to use many simpler  
> functions - but their combination is more complex.
> 
>> "hiding details" only works if the client programmer really doesn't
>> care about the details.
> 
> Why should he care? Isn't "hiding implementation details" a good design  
> principle?
> When I use urlopen, I don't even care of the underlying socket  
> implementation. I don't care which interfase the request is sent thru. I  
> don't care if the answer got fragmented and some packets had to be  
> reassembled. urlopen gives me something that looks like a file, and I just  
> read() from it.
> 
>>> Back to your example, the fact that a decorator builds a higher order
>>> function, does NOT make it more complex - because the programmer does  
>>> not
>>> see that. In fact, hiding the details makes it simpler.
>> Yes, the programmer does see that. The example decorator I posted
>> requires about a zillion preconditions to work correctly and will fail
>> in weird ways when those preconditions are not satisfied. The
>> programmer is interested in the crazy failures he or she will
>> experience. I dare you to try and implementing the code both as a
>> decorator and as a function, then write the unit tests and
>> documentation. The complexity of those three items together
>> (implementation + tests + documentation) will be much higher for the
>> decorator choice because the complexity of the decorator
>> implementation is a bit higher than using a plain old function.
> 
> Testing the decorator is as hard as testing any other function. Testing  
> the decorated functions might involve *only* checking if the decorator is  
> actually used for those functions.
> Going to your posted example, I don't see the difference - I should say, I  
> don't see the advantage. Using a decorator hides some implementation  
> details and reduces coupling between modules, both good things on "my"  
> book; your function with no decorator does quite the opposite, and doesn't  
> look like good coding style (on "my" book, of course).
> 
>> Note also that it is extremely rare to see well-documented or
>> well-tested code, which means that the programmer WILL have to analyze
>> the implementation which means that implementation complexity matters
>> a lot.
> 
> In any case, that would require testing and analyzing ONE function (the  
> decorator) instead of inspecting a zillion repetitions of the same code  
> that, when being wrong, have to be located and fixed on all those places.
> 
> Really, I still can't understand how you can defend such silly things -  
> unless we are talking about different things.
> 


FACADE

Intent : Provide a unified interface to a set of interfaces in a
subsystem. Facade defines a higher-level interface that makes the
subsystem easier to use.

GoF Design Patterns. pp.185









More information about the Python-list mailing list