I'll fix it later


proof-post-icon

Come on man, it's an emergency, and we need to fix this right away, so ...

"I'll fix it later"

I mean far be it from me to suggest that you're making that up.

I believe we should give people the benifit of the doubt.

People wouldn't simply lie during a code review to get me to approve a thing and then just ... never follow up...

so, show me one

Fundimentally, we have to assume we're working with good faith actors, right?

So it seems fair to just approve the PR, once they show a pair of commits where: - The first one sucks, but they said "i got u next time dawg" and - The second one actually fixed the suck from the first commit.

Oneliners? In my crontab?


You can neatly put all your logic into a signle class, and then have a nice little factory that looks at @ARGV.

If your class has prod configs as defaults, then your crontab looks like this:

* * * * * perl -MMyApp::Script::CleanupExpiredEntries \
                -E'MyApp::Script::CleanupExpiredEntries->new_from_args->run'

Because you don't have any code in a bin/run-me script, you can neatly write tests for all your functions by either sub-classing your ::Script to replace your database access logic or by by straight-up replacing the method for the duration of your sub-test with

{
    local *MyApp::Script::CleanupExpiredEntries::fetch_from_db = sub  { ...}
    ...
}

The most notable downside is that some day someone might introduce some code that uses Log::Log4perl, and a config config that references $0:

log4perl.appender.LOGFILE.filename=sub {
    my $name = ( map s{ [.]pl $ }{}xr, split m{/}, $0 )[-1];
    "/var/log/$name/$name.log" }

which means you'll get a mail a minute saying:

 Can't sysopen /var/log/-e/-e.log (No such file or directory)
    at /usr/share/perl5/Log/Log4perl/Appender/File.pm line 140.

which might not be the kind of thing you want to see after taking a couple of days off.

I like perls scoping


TL;DR: I think it's chill that perl has both lexical and dynamic scoping.

for my $thing (@things) {
    local $ThingFinder::LogLevel = 9;

    print "I have $thing";
    if (my $thing = $thing->get_more_specific_things()) { 
        print "I have found this thing: $thing";
    }
}

Lexical variables!

Variables who are only declared / visible within their scope.

my $item = Thing->new();               # <- declare a lexical variable
                                       #    and shove an object in there
                                       #
for my $thing ($item->fetch_things) {  # <- $thing only exists within the loop
                                       #
    my $item = $thing>get_item();      # <- this $item masks the $item above
    $item->do_stuff();                 # <- do_stuff can't see either $item
                                       #    (though the inner one will be "self" in the call)
                                       #
}                                      # <- inner $item is DESTROYed here.

Lexicals are the power house of the closure:

sub thing_maker {
    my $thing = shift;                  # <- $thing will live past the end of the
                                        #    call to thing_maker
    return sub {                        # <- return a code-ref
        "I made this thing: $thing"     # <- This reference here keeps $thing alive.
    }
}

my $code = thing_maker("very good thing here");
print $code->()                         # "I made this thing: very good thing here"

Globals or Package variables!

These are the kind of variables you get if you don't use strict 'vars'.

#!perl
$half = $ARGV[1] / 2;            # <- $half isn't declared with my/our/state
                                 #    so it's ours 
print "Half of that is $half\n"  # "Half of that is 5"  (or whatever)

These are kind of pesky because the stuff you assign to them is only DESTROYed when the variable is assigned over or the interpreter shuts down.

You can see them from outside the package

You have a variable in a package:

package ThingFinder;
our $LogLevel = 4;
1

... and you can see the values in it:

use ThingFinder;

sub show_loglevel {
   say "It's $ThingFinder::LogLevel"; # It's 4
}

... sadly anyone can write to it too:

# Set the value for everyone forever:
$ThingFinder::LogLevel = 'just any old garbage'; 

These variables are super helpful for configuration when your package exports functions.

You can override the value for those called inside a block with local

$ThingFinder::LogLevel = 4;             # <- Set the value for everyone forever
ThingFinder->show_loglevel()            # "It's 4"

{
    local $ThingFinder::LogLevel = 9;   # <- Set the value until the end of the scope
    ThingFinder->show_loglevel()        # "It's 9"
}

local works on other stuff, like the symbol table, or just regular old hashes, which is also chill.

That's it.

I just think that's neat.