Making your Perl application more manageable
Introduction
Long-lived Perl applications tend to accumulate a particular kind of problem: they work, but only on the machine they have always run on. Dependencies were installed globally years ago, the database is the production one or nothing, and the deployment process lives in somebody’s memory.
None of that requires a rewrite to fix. Three fairly small changes make an inherited Perl codebase much easier to work with, and none of them need you to touch the application logic.
Isolate your dependencies with local::lib
The most common problem is modules installed system-wide with cpan as root. That makes it impossible to know what the application actually depends on, and upgrading a module for one application risks breaking another.
local::lib solves this by keeping modules in a directory you own, rather than in the system Perl’s library path:
cpan local::lib
Then set up the environment for the current shell:
eval "$(perl -Mlocal::lib=~/perl5)"
That exports PERL5LIB, PERL_MB_OPT and friends so anything you install from that point on lands in ~/perl5, and anything you run picks it up. Adding that eval line to your shell profile makes it permanent.
With that in place, cpanm no longer needs sudo, and you can throw the whole directory away and rebuild it when you want to check that your dependency list is actually complete. That last part is the real benefit: it turns “which modules does this need?” from guesswork into something you can test.
If the application doesn’t already have one, this is also the point to add a cpanfile listing its dependencies, so the next person doesn’t have to reconstruct them from failed test runs.
Give yourself a disposable database
The second obstacle is usually the database. If the only way to run the application is to point it at a shared MySQL or Oracle instance, then local development is slow, risky, and impossible offline.
Where the application talks to its database through DBI without leaning too heavily on vendor-specific SQL, DBD::SQLite is worth trying as a development target. It needs no server, the whole database is a single file, and the driver is bundled with SQLite itself, so there is nothing to provision:
cpanm DBD::SQLite
The connection string is all that changes:
my $dbh = DBI->connect("dbi:SQLite:dbname=dev.sqlite", "", "");
Because the database is just a file, you can commit a seeded copy, reset it between test runs by deleting it, and give every developer their own without a server anywhere.
It is not a perfect substitute — SQLite’s type handling is looser than most servers’, and anything using stored procedures or vendor-specific functions won’t port — so treat it as a development and testing convenience rather than a promise that production behaves identically. Even partial coverage is a large improvement over having no local environment at all.
Get it into version control
The third change is the most obvious and the most frequently skipped: if the application isn’t in git, nothing else you do is safe.
Inherited Perl applications are often edited in place on the server, which means there is no history, no way to see what changed before something broke, and no way to review a fix before it goes out. Even initialising a repository from the current state of the production directory is worth doing, because it gives you a baseline to diff against.
Be careful about what goes in on that first commit. Configuration files with database credentials, generated files, and the ~/perl5 directory from the first section all belong in .gitignore rather than in the history, and credentials that have already been committed need rotating rather than just deleting.
Where this leaves you
None of this modernises the application. What it does is make it possible to check out the code, install its dependencies without root, point it at a throwaway database, make a change, and see the change fail or pass — all without touching a shared environment.
That is usually the thing standing between a legacy Perl application and being maintainable again. The larger clean-up is much easier to justify once you can safely experiment.