Wow. Those are some really horrible suggestions for how to solve this problem.

A well-designed component gets information from the caller by the caller passing in the information to the component. Having components try to reach up into the parent and pull stuff out of the parent is a much worse design choice than even just the using of a global variable.

You usually pass data into a module either when you 'use' the module or by calling subroutines or methods from the module. For example:

use Your::Module( $log_file );

or

use Your::Module; Your::Module->set_log_file( $log_file );

The first example leads to some subtle gotchas as well, so just use the second method (just like the designers of Log::Log4perl did):

package Your::Module; # ... sub set_log_file { my( $we, $log_file ) = @_; Log::Log4perl->init( \"... $log_file ..." ); }

You don't see Log::Log4perl telling you, "Just set the $log_conf global variable in your package to contain your configuration string and Log::Log4perl will go pull the value from it".

Having the child module have to know the name of the variable and forcing the parent to make that variable global are both design mistakes. Using PadWalker is particularly crazy. Can you imagine Log::Log4perl saying further "Note that if you declare the variable to be hidden from other modules by using 'my', Log::Log4perl will thwart your stated goal of hiding the variable and will dive into the guts of Perl to find the variable anyway so you might want to add a comment to make this clearer: my $log_conf # Not really private!".

Worse than the "we'll pass the information by both sides happening to use the identical name" part of this is that you also put a subtle dependency on the order in which things get done. Consider this example:

package main; use strict; use Log::Log4perl; use Your::Module; our $log_file = ...; Log::Log4perl->init( ... );

and

package Your::Module; Log::Log4perl->init( \qq< ... $main::log_file ... > );

So, after you notice that this isn't working, you go to fix the order in which things are done using a more awkward layout:

package main; use strict; use Log::Log4perl; our $log_file = ...; Log::Log4perl->init( ... ); use Your::Module; # Must happen after $log_file is set. DON'T MOVE UP!

But that doesn't work either.

Pass in the data needed by code when you call the code that needs the data. Then the audience playing at home has a better chance to more quickly understand what is going on.

But I also thought that Log::Log4perl dislikes being initialized more than once in the same process. So I suspect that your design has even more problems in it than just the passing of the log file name. Indeed, seeing you repeat the identical configuration for Log4perl in two places looks like the sign of poor design to me. It sounds like you noticed that you were computing the name of the log file in two places only because you didn't manage to always come up with the same name in both places.

Computing the same thing in two places using code that was copy-and-pasted is poor design. Copying and pasting code is always a bad idea (usually a really bad idea). But declaring it unacceptable for the two sides to come up with different answers is even worse.

Repeating the configuration and initialization of Log::Log4perl looks like a design mistake. Of course, I find the initialization of Log::Log4perl to be terribly awkward. The way one uses Log::Log4perl is moderately awkward, something that I'd probably consider a good choice in most modules but one that I find unfortunate for a logging module.

I believe that a logging module should go to unusual lengths to make it extra easy to add logging so that more logging is likely to get added before the need for the logging actually comes up. When a problem is found with some code and I need to debug what is going on in a deployable service, then it is often inconvenient to reproduce the problem in a way where I can use the Perl debugger. So being able to just turn up some existing logging and get a lot more details about what is going on is often a huge time saver.

So Log::Lager tries to make it really easy to add some trace. The module needs further enhancements (some of which are happening now, at least in the git repo, soon to be on CPAN, I hope). So you might also look into using it.

- tye        


In reply to Re: Can I from within a module access variables from the calling program? (modular design) by tye
in thread Can I from within a module access variables from the calling program? by HJO

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.