advice about `correct' use of decorator
ricaraoz at gmail.com
Mon Sep 3 12:28:45 CEST 2007
Gabriel Genellina wrote:
> En Wed, 29 Aug 2007 07:32:21 -0300, BJörn Lindqvist <bjourne at gmail.com>
>> 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>
>>>> 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
>> "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
> 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
>>> 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.
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