Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re: [RFC] Review of module code and POD

by kcott (Archbishop)
on Apr 01, 2021 at 02:58 UTC ( [id://11130656]=note: print w/replies, xml ) Need Help??


in reply to [RFC] Review of module code and POD

G'day Bod,

As far as I can see, there's nothing horribly wrong with what you've presented; however, there are a number of things I would have done differently. The following is very much biased towards my own preferences: pick and choose any bits you like; skip the bits you don't want; feel free to ignore all of it. I've also added some useful POD-related documentation links.

I write a lot of modules. The majority would be for $work; although, I do write quite a few for personal use. Regardless, these are not for CPAN: the $work ones are Commercial in Confidence; the personal ones are too specific to my needs, or in some cases just testing ideas, and are not considered to be of general usefulness.

Having said that, I still write these modules as if they were going to be uploaded to CPAN, and include: POD with the code; standard files such as Makefile.PL, MANIFEST, README and Changes; tests in a t/ directory; and so on. This allows me to, amongst other things: test changes (make test); easily install the modules (make install); create distributions (make dist) which I can transfer to other machines (e.g. scp to $work). I also find the POD to be exceptionally useful: six months or so after completing a module, I can rarely remember the exact details of every function and method, particularly when it comes to optional arguments and complex return values (e.g. array and hash references) — perldoc ModuleName makes my life so much easier.

I never sit down and write all the files needed for the type of module described above; instead I use Module::Starter with the Module::Starter::PBP plugin. The latter is mainly for the excellent templates and does not represent a slavish adherence to "Perl Best Practices" guidelines.

I have multiple config* files for my various uses. As an example, here's the currently active one for personal modules using Perl v5.32:

ken@titan ~/.module-starter $ cat config author: Ken Cotterill email: kcott@cpan.org builder: ExtUtils::MakeMaker plugins: Module::Starter::PBP template_dir: /home/ken/.module-starter/P532

I have modified the templates for my own preferences. For personal modules, that can be pretty much whatever I want. For $work modules, there are certain constraints, policies, and so on, that I need to take into account (e.g. specific Perl version, copyright text, etc.).

There are three test files that I always add to the templates. These use Test::Pod, Test::Pod::Coverage and ExtUtils::Manifest.

The idea behind all of this is to create templates once, then let module-starter create as many module frameworks as I want, all with the same, consistent look and feel. Obviously, I still need to fill in details, such as the description of functions, but all of the boilerplate has been done for me and I can pretty much forget about that part of the process. Partly DRY; mostly "the first great virtue of a programmer": laziness.

Here's the POD documentation to which I alluded earlier:

perlpod
This is the basic documentation and a handy reference. If you're not familiar with it, check out the use of multiple angle brackets allowing nesting of "Formatting Codes" (it's near the end of that section).
perlpodspec
This is the gory details. It's probably more geared to those writing POD parsers and the like, but still has useful information. I'd generally only use this if I couldn't find sufficiently specific information in perlpod.
perlpodstyle
This has information on the standard sections of a manual page. You may find this useful.

Things I would have done differently (in no particular order) and bear in mind, as I said above, these are my personal preferences:

  • I put all the code first; and all the POD last.
  • I always start POD with =encoding utf8.
  • I generally put whitespace before and after code blocks (if, while, etc.).
  • I try to keep lines under 80 characters; I'll go out of my way not to exceed 120 characters. This simply makes reading the code easier. I acknowledge that this is not always possible, but mostly it is. As an example, I'd prefer:
    my $dbh = DBI->connect( "dbi:mysql:$Bod::Variables::db_prefix$env:localhost:3306", "$Bod::Variables::db_username", "$Bod::Variables::db_password" );
  • Your use of $Bod::Variables::varname, locks you into a single class. Consider this which allows subclassing:
    # Uncomment one of these # my $bvar = Bod::Variables::->new(); # my $bvar = Bod::Variables::Special::->new(); my $dbh = DBI->connect( 'dbi:mysql:' . $bvar->db_prefix() . "$env:localhost:3306", $bvar->db_username(), $bvar->db_password() );
    Obviously, as I have no knowledge of Bod::Variables, that's highly contrived with a lot of guesswork; however, I hope you get the idea of the increased flexibility it offers.
  • I'd generally use more meaningful names than find() and add(); perhaps find_people() and add_person() would aid in reading and understanding the code.
  • The get() function could also do with a more meaningful name. If it's part of the API, document it in the SYNOPSIS; if it's not, prefix it with an underscore, to nominally indicate that it's private, and remove it from the POD (if renamed to _get_person_info(), the function is so simple that it wouldn't even need a comment).

— Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11130656]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2024-04-19 10:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found