Keep in mind that for non-trivial code an optional dependency can cause spaghetti-like code with conditionals peppered throughout the code base:
if(exists $INC{'Example/Module.pm'}) {...}
...or...
if (__PACKAGE__->can('example')) {...}
...or any of a number of other strategies for detecting if the optional module got loaded. This is a situation where it's usually better to encapsulate the optional dependency so that the calling code doesn't have to care whether it was available or not:
package SomeThing;
use Exporter;
BEGIN {
if (eval "require MyOptional; 1;") {
MyOptional->import('foo');
}
else {
*foo = sub { # fallback code here. };
}
}
use parent 'Exporter';
our @EXPORT = qw(foo);
1;
package main;
use SomeThing;
foo();
Now everywhere you wanted foo() you can just call it and not worry about whether or not it got loaded at startup by an external dependency, or by a fallback sub that you created yourself. This is just one of many ways to do it. An encapsulating OO class might work better, or dependency injection into a consuming object could be better; it depends a lot on your use case. But the goal is to reduce the pervasiveness of conditional logic in your code to only the one place.
|