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

I am currently updating an old perl website. The site itself runs via a custom package, using CGI::Application

There are many global variables which I'm refactoring out, not least because I want to start using mod_perl.

These globals are defined in a special globals package using vars::global and simply used in the code like $my_global_variable

They comprise of three types of variable; user properties, "static" information like paths or images folder, and page specific information like breadcrumbs.

Luckily, I have a $self object passed to all the different subs that generate website page information. I have created these methods in the main website package:

############### sub set_param { ############### my $self = shift; my ($name, $value) = @_; $self->{$name} = $value; return; } ############### sub get_param { ############### my $self = shift; my ($name) = @_; return $self->{$name} || ''; }
And so I can use the variables like so:
$self->get_param('breadcrumb');
This work perfectly, but before doing the major refactoring work, I wanted to check that I'm on the right track. Essentially, my question is whether this is the accepted/best practice for dealing with these kind of variables, which are needed throughout the code (i.e. in the subs for page types and also in the main package itself which deals with rendering the page and the master template for all pages).

Also, for the "static" variables that don't change in the code, I can do it the same way as above, but is there a better way i.e. so they don't have to be re-populated within the same thread once I start using mod_perl.

Thanks

Replies are listed 'Best First'.
Re: Best Practice for Replacing Globals
by kcott (Archbishop) on Apr 19, 2023 at 20:08 UTC

    G'day beaker121,

    Welcome to the Monastery.

    You'll need to show us the code where these global variables are defined; or, at least, a small extract of that code such that we can understand what is going on. Your prosaic description is unclear. Your posted code does not reference any global variables.

    [Aside: I appreciate that this is your first post, so you probably didn't know about this, but please see "What shortcuts can I use for linking to other information?". As an example, writing vars::global, instead of just vars::global, makes referencing modules you're discussing a lot easier.]

    By the way, "return $self->{$name} || '';" looks dodgy. If the actual value was zero, did you really want to report it as a zero-length string. I don't know enough about your code, but suspect exists() and/or defined() might be useful here.

    — Ken

      > As an example, writing vars::global

      Oh I wasn't aware this is an actual CPAN module ... thanks! :)

      All lowercase is a strange naming decision, though.

      Cheers Rolf
      (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
      Wikisyntax for the Monastery

Re: Best Practice for Replacing Globals
by marto (Cardinal) on Apr 20, 2023 at 08:18 UTC

      I have to say that this has not been my experience. It has proven quite easy in the past to migrate old, crusty CGI-based applications to mod_perl using ModPerl::Registry and especially so compared to having to re-engineer the entire codebase to work with a new framework.

      The various web frameworks are fine for green-field projects but impose a significant burden on the developer when migrating in an existing application like this.


      🦛

        "compared to having to re-engineer the entire codebase to work with a new framework."

        "The various web frameworks are fine for green-field projects but impose a significant burden on the developer when migrating in an existing application like this.

        In this use case, mojolicious has you covered, adding one hook allows the existing codebase to work as expected. I've used this in the past without issue.

        "I have to say that this has not been my experience."

        I've rewritten several legacy CGI::Application codebase with Mojolicious/(or Mojolicious::Lite), the learning curve wasn't steep, I ended up with something faster, fewer lines of code and less cludgy than before. Of course YMMY

        Update: Also, for the uninitiated, mod_perl binds you to using Apache.

Re: Best Practice for Replacing Globals
by tobyink (Canon) on Apr 20, 2023 at 07:21 UTC

    Instead of $self->get_param( 'breadcrumb' ), try $self->get_breadcrumb().

    Consider how they would each act if you misspell "breadcrumb" as "braedcrumb". $self->get_param( 'braedcrumb' ) will silently return false and you'll spend half an hour trying to figure out why the site's breadcrumb links aren't displaying correctly, but $self->get_braedcrumb() will give you an instant "that method doesn't exist" error.

Re: Best Practice for Replacing Globals
by LanX (Saint) on Apr 19, 2023 at 13:40 UTC
    This is hard to tell by a verbal description and without seeing an SSCCE.

    Basically: The more you need to refactor, the riskier.

    Some thoughts:

    • Is it a one file project?

      If you use file scoped my lexicals instead, you won't have to change the code using those vars.

    • If it's multi-file project,

      you could use a tie interface to implement those methods (in FETCH and STORE) with my vars, while sticking with the old syntax.

      Those methods will come with a speed penalty, but you can also use it to monitor where your vars are actually used and gradually replace them with real lexicals.

    • Regarding modperl,

      I'm not sure if that's still state of the art, I'd rather look for fastcgi or similar first.

    Cheers Rolf
    (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
    Wikisyntax for the Monastery

      It's a large project with many files. I don't really know what you mean by replacing them with real lexicals as I don't see that as being possible, these values need to be used across the program as a whole. For example, I'm trying to move towards more OO approach and was thinking of having the user information (preferences, username after session has been validated etc.) in its own package.
        > I don't really know what you mean by replacing them with real lexicals

        If a package var is used only inside a single file, you can use a lexical without tieing it.

        > these values need to be used across the program as a whole.

        Hmm, as I said I need to guess to understand your situation.

        For instance one of your descriptions fits for constants. I can't see the need to change them in a modperl environment.

        And you may be able to go the inverse way, keep those package vars and tie them to a class which adapts to the modperl runtime environment by accessing its values in a lexical hash.

        Again plain guess work without you showing an SSCCE.

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery