Enforcing Simple Standards with One Module
It's fair to say that at our consulting company, we work with many clients who use Perl heavily. The "preamble" of their Perl code is either an ad-hoc mixture of features, or stock boilerplate like this which gets cut-n-pasted all over the place:
use strict;
use warnings;
use v5.24;
use feature "signatures";
no warnings 'experimental::signatures';
use utf8::all;
use Carp;
Both of those approaches are dead wrong. The "ad hoc" pragma list means it's hard to be sure what features are or are not available. The "standard boilerplate" approach means cutting-n-pasting and then hating yourself when you have to change that standard boilerplate.
Modern::Perl is a nice middle ground for avoiding this, but it may not be the features you want. For example, our free-to-play narrative browser game, Tau Station, doesn't use the C3 MRO because we don't use multiple inheritance (note: we enforce C3 on our DBIx::Class classes, of course).
Instead, we have our custom boilerplate, wrapped up in Veure::Module
.
It looks like this:
package Veure::Module;
use 5.24.0;
use strict;
use warnings;
use feature ();
use utf8::all;
use Veure::Carp;
use Import::Into;
sub import {
my ($class) = @_;
my $caller = caller;
warnings->import;
warnings->unimport('experimental::signatures');
strict->import;
feature->import(qw/signatures :5.24/);
utf8::all->import;
Veure::Carp->import::into( $caller, qw(carp croak vcarp confess) );
}
sub unimport {
warnings->unimport;
strict->unimport;
feature->unimport;
utf8::all->unimport;
Veure::Carp->unimport;
}
1;
__END__
=head1 NAME
Veure::Module - Use modern Perl features
=head1 SYNOPSIS
use Veure::Module;
=head1 DESCRIPTION
This module is a replacement for the following:
use strict;
use warnings;
use v5.24;
use feature 'signatures';
no warnings 'experimental::signatures';
use utf8::all;
use Veure::Carp qw(carp croak);
Now, for all of our modules, we can just drop use Veure::Module;
at the top and our development work is much easier, and standardized.
The use of strict
and warnings
is obvious.
utf8::all
might be controversial, but we've found it helpful.
Veure::Carp
is our internal version of Carp
(if called from Template Toolkit, it tells us the exact template name and also dumps environment variables).
A future version of this might include the autodie
pragma. We only need to add it in one place and it should be backwards-compatible (we'll see).
The subroutine signatures feature, however, is the killer feature. If you're not using them, you should be, even if they're still experimental. We have a few clients who've made the switch and I've spoken to many others who have, too. This is the one experimental feature that more and more Perl shops are adopting. The reason is simple: your code will be more correct. Pass in the wrong number of arguments and it will die a horrible death. This has saved us so much grief in production that it's worth risking its experimental status.
When you're working on an "enterprise" code base, having standards is critical. I know that's something that many Perl devs don't like to hear (I've seen a dev get let go because they wouldn't adjust their brace style), but if you don't have standards, codebases get messy quickly. It's never too late to start. I know that Veure::Module
won't meet your exact needs, but the idea of building standards into a single module is worth the trouble. Combine that with Perl::Critic
and Perl::Tidy
and you're well on your way to reigning in the headache of large codebases.
And for what it's worth (I know that LOC is a terrible metric), Tau Station is now around 1/3 of a million lines of code, if you also count what we've built on the front end.
As always, drop me a line if you need expert Perl software development.
Most of my code runs under a version of current version of perl I've built and loaded with distributions I use. However I have a couple of scripts for bootstrapping which run under the system perl but use quite a few of my own pure-perl modules. These modules are not-specific to bootstrapping so include my version of a Modern::Perl-inspired boilerplate module. The first thing the import() in that module does is return when running under system perl.
FWIW the boilerplate imports; I have not done anything for features yet. Modern::PBP::Perl has nice %FEATURES & %WARNINGS tables up to 5.24 'utf8::all' ->import::into($callerpackage, 'NO-GLOBAL'); 'English' ->import::into($callerpackage); 'IO::File' ->import::into($callerpackage); 'IO::Handle' ->import::into($callerpackage); 'autodie' ->import::into($callerpackage); if ($CARPALWAYBUTQUIETER) { # don't need the verbosity of java-style full-stacktrace 'Carp::Always::ButQuieter'->import::into($callerpackage); } else { 'Carp::Always'->import::into($callerpackage); } 'Data::Printer'->import::into($callerpackage, 'colored' => 0, 'quotekeys' => 1, 'scalarquotes' => "'", );
FWIW some boilerplate modules in CPAN Modern::PBP::Perl Modern::Perl features strictures pragma Sympatic features & modules utf8::all features & modules & more
Looks like you have a runaway " literal in the
use feature
statement. Or is that some really obscure Perl-Foo that I'm unfamiliar with?Thanks Bill! That's fixed :)
No it's not :-)
use feature "signatures';
OK, i have some problems with the feature->unimport.
To keep everything complicated here is the setup:
I can't get something working for both perl versions.
it looks like that feature->unimport simple can't unimport 'try' or perhaps any feature?!
OK, to add some juice:
do the trick (so disable 'try' for the complete file i guess?!)