Ben Hengst gave a talk at Portland Perl Mongers last night about dependency injection and inversion of control in Perl. He said something completely true. "You've probably already done this, even though you didn't know it was called this."

At its core, dependency injection is a formalization of the design principle "Don't hard-code your dependencies." Consider the code:

sub fetch { my ($self, $uri) = @_; my $ua = LWP::UserAgent->new; my $resp = $ua->get( $uri ); ... }

That's not bad code by any means, but it's a little too specific and a little less generic due to the presence of the literal string LWP::UserAgent . That might be fine for your application, but that hard-coding introduces a coupling that can work against other uses of this code. Imagine testing this code, for example. While you could use Test::MockObject to intercept calls to LWP::UserAgent 's constructor, that approach manipulates Perl symbol tables to work around a hard coded dependency.

An alternate approach uses a touch of indirection to allow for greater genericity:

use Moose; has 'ua', is => 'ro', default => sub { LWP::UserAgent->new }; sub fetch { my ($self, $uri) = @_; my $ua = $self->ua; my $resp = $ua->get( $uri ); ... }

Now the choice of user agent is up to the code which constructs this object. If it provides a ua to the constructor, fetch() will use that. Otherwise, the default behavior is to use LWP::UserAgent as before.

Adding one line of code and changing one line of code has provided much more flexibility.

An alternate approach is to allow setting ua through an accessor instead of a constructor, but as far as I can tell the only reason to do this is if you're stuck in The Land of the Java Bean Eaters.

While the existing literature on inversion of control and dependency injection tends to throw around big words which have the effect of obfuscating rather than enlightening, the basic concepts is simple. You've probably already done it. Now you know what it's called and why it's useful, and probably also can find ways to use it where it helps.

(See also: how you select a DBD with DBI.)