John N8UR has asked for the wisdom of the Perl Monks concerning the following question:

I've created a handful of modules that each contain one fairly complex function (maybe a couple of hundred lines of code). They are all wrappers to manage and convert PostScript files. For maintainability, I'd like to keep each one in its own file. I would like to know the proper way to manage this, assuming I might want to share these on CPAN. I'm using the "module-starter" tool to create the framework.

I see three options:

I'd like any guidance on this so I do the right thing.

Thanks!

Replies are listed 'Best First'.
Re: Building Good Modules
by 1nickt (Canon) on Feb 13, 2019 at 01:06 UTC

    Yes, I concur with talexb that option 2 is the way to go.

    Start a project directory and make subdirs:

    lib/ t/ bin/

    Put your modules in lib/ using a top-level dir for the top level part of your namespace (if you one day distribute to CPAN you will want a distro name under PostScript and not put your modules directly under the top level) and maybe using subdirs for segments of your desired namespace:
    /lib/YOUR_DISTRO_NAME/PSjoin.pm /lib/YOUR_DISTRO_NAME/PS2png.pm /lib/YOUR_DISTRO_NAME/PStopdf.pm /lib/YOUR_DISTRO_NAME/Utils/Frobnicate.pm
    and use them like
    use YOUR_DISTRO_NAME::PSjoin; use YOUR_DISTRO_NAME::Utils::Frobnicate;

    Add that whole directory tree to a version control system like git. Do it first! Then write tests in t/ for all the things. Maybe use subdirs there for the different modules, maybe it's by functionality, maybe both: that's up to you.

    Then when you want to build a distribution in the future your files will be in the proper structure. You don't have to worry about such packaging tools now, but preparing for them is wise.

    Hope this helps!


    The way forward always starts with a minimal test.
      Thank you Alex and 1nickt! You've confirmed what I was hoping was the right way to do it. I'm already part way down the road -- I used the module-starter tool to set up the directory structure (at the moment, for the separate trees, but I'll merge them), and I use github.

      If I have multiple .pm files in the bin/ directory, will the normal sequence of perl makefile.PL; make ; etc. catch all the files, or do I need to manually edit the makefile to have it find the multiple .pm files? Thanks again!

        If I have multiple .pm files in the bin/ directory

        Don't put .pm files in the bin/ directory - put them in the lib/ directory instead. Then yes, they should be found automatically by the build and test process.

Re: Building Good Modules
by talexb (Chancellor) on Feb 12, 2019 at 22:24 UTC

    To answer your first question, my opinion would be to choose option two -- make them be separate modules, but keep them within one project.

    I'm not as much an expert about tools to properly build the distribution, but I've always been a fan of Module::Starter. Create a module skeleton, add your modules in, and you've got version 1.0! Hopefully more experienced module developers will chime in with their comments.

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: Building Good Modules
by Ea (Chaplain) on Feb 13, 2019 at 10:14 UTC
    If you're looking for more of a tutorial approach to creating modules, have a look at [RFC] Discipulus's step by step tutorial on module creation with tests and git which is looking for feedback. Comments are positive, but it might benefit from the insight of someone actually using it in anger. It's the best way of finding out if there's something missing.

    Ea

    Sometimes I can think of 6 impossible LDAP attributes before breakfast.

    Mojoconf was great!

      Thanks, that looks really helpful!
Re: Building Good Modules
by eyepopslikeamosquito (Archbishop) on Feb 13, 2019 at 08:46 UTC
      Thanks!
Re: Building Good Modules
by stevieb (Canon) on Feb 13, 2019 at 21:47 UTC

    I'm in agreement with other Monks here... put each one into its own module file. Do not put all of this within a single module/library.

    That said, if there are benefits to separating them out into separate distributions, such as does the one someone wants (PS2png for example) install significantly faster than installing the bundle, is there one out of the many that cause difficulty during install where the others don't, or will the parent ever become extensible where you will add more later?

    In those cases (and I've only named three), I'd break it up; each one a separate distribution, then possibly create a top-level distribution that when installed, will bring in all of them together:

    Postscript::Objectives; - Postscript::PSjoin - Postscript::PS2png - Postscript::PStopdf

    ...for example. That way, your users will be able to install each one individually, or all of them as the top-level bundle distribution.

    Drawback to this approach is that there's usually more documentation that has to be created and kept up-to-date, but that's not usually too much of a problem, as you're writing POD for each module anyhow.

    Also, typically, that'd mean that you've got several locations for each part of source code (repositories, as it were), so there's a bit more effort on the back-end software management front there. That said, testing can still be all performed for everything in the parent library for all sub-distributions, because it brings in all of them anyhow. This is exactly how I maintain RPi::WiringPi

    Update: Forgot to add about one of the benefits of separate distributions... if you ever add a new module to the collective, you need only slight changes to the top-level parent one. Likewise, if they are all separate, fixing a bug in a sub-distribution does not at all affect the efficacy of the top-level one; ie., there's no chance that if you break a sub-dist via an update of any sort, it'll only affect that distribution only; it won't cause a collapse of the whole shebang, even if by mistake and it gets past all of your best efforts of ensuring things don't cascade into a nightmare.