in reply to Factory classes in Perl
However, in Perl we have CPAN from which we install our modules...this allows us to specify dependencies be be installed when we install our module. In this Perl Advent Calendar example, why would we create a ReindeerFactory instead of just forcing our module to install Robo-Reindeer if that's the one we prefer?
IMHO, you're right to question this. Factory classes are often used in strongly typed languages like Java, I myself have for example written a Logger interface with different underlying implementations. The important thing to note is that the user of my library specifically chooses which implementation they want, and the factory class is helpful because the language is compiled and strongly typed; it's not as simple as Perl's "a constructor can return whatever it wants".
However, the conditional loading of modules depending on something outside of the user's control is something that I nowadays think should be very sparingly used for exactly the reason you hint at: if I've written my code to depend on a certain module or functionality (RoboReindeer), then trying to adapt my code to environments where that module isn't available (BioReindeer-only) is often more work than either backporting RoboReindeer to that environment, or simply declaring that my code requires RoboReindeer, with whatever limitations that brings.
For me, it comes down to the question of well-defined behavior. If I'm writing a library, I don't like telling the user of my code "you ask for a reindeer and maybe I'll give you a BioReindeer or maybe a RoboReindeer, why do you care?" because more often than not there is a difference between the two that will have my user jumping through hoops to cope with that difference down the line (if ( $reindeer->isa("RoboReindeer") ) { do_this() } elsif ( $reindeer->isa("BioReindeer") ) { do_that() } else { die "unknown species" }).
On the practical side, let's say I write a library that uses *Reindeer, and when the user installs my library they only have BioReindeer installed, so only that subset of my module's test suite gets run. If they install RoboReindeer later, my test suite may never get executed against the RoboReindeer they installed, which again may lead to problems.
So for these reasons nowadays I lean very strongly towards simply saying "the users of my library are getting RoboReindeers, period".
There are of course exceptions, an important one is the OS-dependent implementation of a platform-independent interface, as choroba indicated - one of the big ones in the Perl core is File::Spec, for example. Another one is the automatic loading of XS-based versions of otherwise pure-Perl modules when they are available (as long as the two really behave identically and the XS version is just an optimization). And a last reason that I can think of at the moment may be if you're trying to gradually transition your code away from one dependency onto the other.
(It's late and I don't have the time to investigate further right now, but I'd be genuinely curious if there are other useful uses for the "recommends" and "suggests" relationships of CPAN::Meta::Spec.)
Update: Thinking about this a bit more, I guess what I am saying is that my experience simply doesn't line up with the premise of the article, in particular the first word:
Often we find ourselves writing code that copes with optional dependencies; Code that will use a module to do amazing things if it's installed, but will muddle through with some lesser code path if that dependency is missing or unavailable on the system.
Instead, I think that most of the time one thinks one is in this situation, there is a different and often more pragmatic solution possible.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: Factory classes in Perl (updated)
by hippo (Bishop) on Jan 09, 2021 at 11:46 UTC | |
by haukex (Archbishop) on Jan 09, 2021 at 14:13 UTC | |
by stevieb (Canon) on Jan 10, 2021 at 03:30 UTC | |
Re^2: Factory classes in Perl (updated)
by Bod (Parson) on Jan 11, 2021 at 23:00 UTC | |
by LanX (Saint) on Jan 12, 2021 at 00:04 UTC | |
by haukex (Archbishop) on Jan 12, 2021 at 11:14 UTC | |
by LanX (Saint) on Jan 12, 2021 at 13:17 UTC | |
by haukex (Archbishop) on Jan 14, 2021 at 15:50 UTC |