Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Just hanging around here inspires me to write all kinds of code/snippets that i would never think of otherwise. Going with Corion's advice about the Facade Pattern (brian d foy wrote an excellent Perl Review article on that pattern by the way - you should read it), here is my quick-n-dirty mini-tutorial:

Say you have a dynamic website whose content is driven by a series of methods/functions contained in some library. Currently, CGI.pm is being used to generate HTML. The library (module) might look like:

package Old; sub new { my ($class,@arg) = @_; my $self = {}; return bless $self,$class; } # pretend these return HTML pages generated via CGI.pm sub index { "CGI.pm index page" } sub page1 { "CGI.pm page1" } sub page2 { "CGI.pm page2" } sub page3 { "CGI.pm page3" } 1;
A cow-orker decides to rewrite these methods and use HTML::Template instead:
package New; sub new { my ($class,@arg) = @_; my $self = {}; return bless $self,$class; } # pretend these return HTML pages generated via HTML::Template sub index { "H::T index page" } sub page2 { "H::T page2" } # page 2 was easier than 1 ;) 1;
They haven't even finished, but the boss is so impressed that (s)he asks you to go ahead and substitute the new methods in. What do you do? You write another "layer" - another module that uses both libraries and delegates which library to use for a given method call. A first naive (as all my first approaches usually are) might look like:
package Interface; use Old; use New; sub new { my ($class,@arg) = @_; my $self = {}; return bless $self,$class; } sub index { return New->new()->index } sub page1 { return Old->new()->page1 } sub page2 { return New->new()->page2 } sub page3 { return Old->new()->page3 } 1;
Before i say why that is naive, here is the test script:
use strict; use warnings; use Interface; my $obj = Interface->new; print $_,$/ for map $obj->$_, qw(index page1 page2 page3);
Go ahead and create those 4 files and make sure everything works. So why naive? Because you probably have more than 4 methods in you old library, many more. I myself am too lazy correctly type in every single method ... why not just use AUTOLOAD? (don't you wish C had one?) Much like the anonymous list i used on the last line of the test script, we could use a similar technique. Here is a revised Interface.pm:
package Interface; use Old; use New; use Carp; sub new { my ($class,@arg) = @_; my $self = {}; return bless $self,$class; } my %new = map {$_ => 1} qw(index page3 page2); sub AUTOLOAD { my $self = shift; my $name = $AUTOLOAD; $name =~ s/.*://; # strip fully-qualified portion #TODO: method name validation! return $new{$name} ? eval "New->new->$name" : eval "Old->new->$name" ; } sub DESTROY {} # good practice - prevents unecessary call to AUTOLOAD 1;
Now all you need to do is add the name of the methods to %new as they are completed. Once Old.pm has been completely deprecated you could get rid of Interface.pm.

By this point you must be asking how all of these name changes are going to affect users ... because they are! In this example, i had the luxury of knowing ahead of time what was going to happen, so i programmed to the Interface.pm module. In reality, i would be programming to the Old.pm module instead. My recommendation is to simply rename the old library to something else, and name your Interface.pm the original old lib name. Then, when the old library has been completely deprecated (oxymoron?), rename the new library to the original old lib name.

Sounds easy, but i know it really isn't. It's hard work no matter how you slice it, but if you provide a seamless way for the lib users to continue to use old methods while new ones are being implemented, then it's probably worth it (er ... whatever it is ...).

Brushing up and writing about the Facade Pattern has nothing to do with my current projects, but i somehow feel more refreshed for doing something new and "not my job" ... oh, and beating the crap outta my drums doesn't hurt either ;)

jeffa

L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)

In reply to (jeffa) Re: How do you avoid "Code Burnout"? by jeffa
in thread How do you avoid "Code Burnout"? by hacker

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (2)
As of 2024-04-16 23:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found