http://www.perlmonks.org?node_id=924672

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

Dear Monks,

I am finally to the point where I have half decent code that I reuse increasingly. In the spirit of avoiding duplication and improving maintainability I found myself putting that in a standalone script. In a nutshell, it is saving specific email attachments to a given path, since I need to get the filenames for further processing, a call from a "master" Perl script via backticks seemed in order.

My naive thought is the following: an external script seems less convenient to retrieve results than returning them back from a subroutine via a reference. However if I start pasting my code as a subroutine in a few different scripts, any improvement I make will have to be updated in all of them.

I suspect making my own module/package may be a way to address this but my code is probably not yet generalized enough and frankly, the thought of making my own module is intimidating for a perpetual newbie like me.

Question:Is the road I am taking (i.e. using external calls) a sustainable approach in the midterm or I am missing something completely obvious?

As always your guidance will be appreciated.

Update: Thanks to all for your encouragement and relevant links. I guess I must be feeling like my son did when I removed the training wheels from his bike... It's probably time for me to get going and build a first module

Update 2: Thanks again to all the posters below, this is the very very best advice I ever had (and followed!). I worship you!!

  • Comment on Naive monk trying to make distinctions among subs, external calls and code reuse

Replies are listed 'Best First'.
Re: Naive monk trying to make distinctions among subs, external calls and code reuse
by luis.roca (Deacon) on Sep 08, 2011 at 00:25 UTC

    My naive though is the following: an external script seems less convenient to retrieve results than returning them back from a subroutine via a reference. However if I start pasting my code as a subroutine in a few different scripts, any improvement I make will have to be updated in all of them.

    This is addressed very directly in Elements of Programming with Perl referencing an earlier subroutine created called commify :

    "Before we delve into the mechanics of building a module, let's consider a simple case that illustrates how a module helps us reuse our code. Recall the function we wrote in chapter 10 for putting commas in numbers. This is a good little function that does one—and only one—thing. Perhaps we have already reused this function by copying or pasting it into other programs where we needed such a function. Reuse of code is a good thing, but this kind of reuse is problematic. First, when we decide we need that commify function, we need to locate one of our previous programs to copy it from. This is not very convenient. Secondly, what if we eventually find that this function has a bug in it and doesn't properly commify a certain numeric input? Now we have to fix this bug and find all the other programs we've written and fix the function there as well. Wouldn't it be better if we could simply write this function in one file and then use it from any other program we create? Well we can do just that."

    ~Andrew L. Johnson, Elements of Programming with Perl, Page 272

    I just did this today for the first time so I thought I'd share what I learned along with a few references.

    Perl has a few tools that will quickly and pretty easily build a module template for you. You can download Module::Starter, a command line tool, that will look like this the first time you run it:

    Usage: module-starter [options] Options: --module=module Module name (required, repeatable) --distro=name Distribution name (optional) --dir=dirname Directory name to create new module in (optio +nal) --builder=module Build with 'ExtUtils::MakeMaker' or 'Module:: +Build' --eumm Same as --builder=ExtUtils::MakeMaker --mb Same as --builder=Module::Build --mi Same as --builder=Module::Install --author=name Author's name (required) --email=email Author's email (required) --license=type License under which the module will be distri +buted (default is the same license as perl) --verbose Print progress messages while working --force Delete pre-existing files if needed --help Show this message Available Licenses: perl, bsd, gpl, lgpl, mit, apache Example: module-starter --module=Foo::Bar,Foo::Bat \ --author="Andy Lester" --email=andy@petdance.com

    Building a module for personal use will only be a few lines:

    $ module-starter \ --module="Foo_Email" \ --author="You" \ ...

    Others will correct me surely but for your own use you wont need much more than that. Dive into the directory created by module-starter and everything is right there waiting for you to add your code. You'll quickly realize it's not as big of a deal as you thought it was and really worth learning. How do I know this? Because it just happened to me. :-)

    Good luck — have fun!

    REFERENCES:


    "...the adversities born of well-placed thoughts should be considered mercies rather than misfortunes." — Don Quixote

      You'll quickly realize it's not as big of a deal as you thought it was and really worth learning. How do I know this? Because it just happened to me. :-)

      I don't believe it!

      You mean to tell me, that you did not blackout!? Bleed from various bodily orifices?! Projectile vomit?!

      I'm shocked! </faint>

      My computer smokes when I jam my file in it

        You're saying I should have noticed that? *sigh* I knew I should haven tried Dist::Zilla. Oh well, today's another day. As always, I'll keep you informed AM. ;-)


        "...the adversities born of well-placed thoughts should be considered mercies rather than misfortunes." — Don Quixote
Re: Naive monk trying to make distinctions among subs, external calls and code reuse
by Kc12349 (Monk) on Sep 07, 2011 at 21:43 UTC

    I think you should bite the bullet here and put in some time to learn the basics of module creation. While creating a formal module in the cpan vein is still a bit daunting for me, making simple things that only I use took relatively little time to get up and running.

    I would suggest you take a look at the FindBin module as a good tool to help you get started testing modules in a project directory. I often use the two below lines of code to point to a lib directory relative where my script is running. $FindBin::Bin will be the directory where your script is running.

    use FindBin; use lib $FindBin::Bin . '/lib';

      Here's the link to the FindBin docs on cpan :)

Re: Naive monk trying to make distinctions among subs, external calls and code reuse
by CountZero (Bishop) on Sep 07, 2011 at 21:36 UTC
    The above link does not work. :(

    This one does: Simple Module Tutorial

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Naive monk trying to make distinctions among subs, external calls and code reuse
by Anonymous Monk on Sep 07, 2011 at 21:05 UTC

    Yes, it is sustainable, in the way that unix/linux is sustainable -- little utilities is the unix/linux way

    If you can make programs, you can make modules, see Simple Module Tutorial