Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's a good way to refactor a monster Perl module into submodules?

I have a Perl module for a project. I have maybe a dozen programs hanging off it and a lot of it is garbage. I hadn't spent much close personal time with DBI before, so that part is fixable, but the big thing is that it is big. Literally 2KLOCs.

It would be easy to break up this function (let's call it Dumb.pm) into separate modules ( Dumb::FormTools , Dumb::Database, etc.) except, as I said, there's lots of programs that already 'use Dumb ;'

I would like to export Dumb::Database's exportable functions through Dumb without having to have variations of this over and over again:

sub my_dumb_function { return Dumb::Database::my_dumb_function( @_ ) ; }

It isn't that I'm above that. It's just that this seems like the dumb and inelegant way of handling the issue. I used the "Don't know no better" excuse once, and once is really more than you get. Help?

like image 764
Dave Jacoby Avatar asked Jan 28 '10 17:01

Dave Jacoby


2 Answers

It's difficult to give you specific advice because different code bases require different strategies. I refactor a module with 500-line subroutines differently than one with small subroutines and a lot of repeated code. If I need to change the interface too, there are different strategies for that.

  1. Get everything into source control. You need to keep the original and intermediate versions.
  2. If you don't already have a test suite, write one. Get the test coverage as high as you can. This test suite is the baseline for preserving the same behavior in the future versions, bugs and all. You're probably going to encounter a program that depends on a bug in the original module.
  3. Start hacking away. At each step, check that the rest still passes the original tests and that the published interface still results in the same behavior.

I think your actual question, though, is "How to I export to the original module that loaded Dumb?". You can provide your own import routine that uses Exporter's import_to_level method. You can import to higher levels than the immediate one that loaded you. The Dumb::Database import can thus load its exports into the namespace that loaded Dumb even though it's Dumb that loads Dumb::Database.

like image 175
brian d foy Avatar answered Sep 19 '22 18:09

brian d foy


Not sure how you are currently using it (does it currently export methods?), but you can set up the new child modules to allow you to import their functions (using Exporter), and then just have the original module explicitly import the now broken out pieces. Something like:

package Dumb;

use Dumb::Database qw(my_dumb_function);

1;

package Dumb::Database;

use base qw(Exporter);

our @EXPORT_OK = qw(my_dumb_function);

sub my_dumb_function { 1; }

1;
like image 34
macabail Avatar answered Sep 21 '22 18:09

macabail