2010-01-28 13 views
5

Tengo un módulo Perl para un proyecto. Tengo tal vez una docena de programas colgando y muchos de ellos son basura. No había pasado mucho tiempo personal con DBI antes, así que esa parte es reparable, pero lo más importante es que es grande. Literalmente 2KLOCs.¿Cuál es una buena manera de refactorizar un módulo monstruo de Perl en submódulos?

Sería fácil romper esta función (llamémosla Dumb.pm) en módulos separados (Dumb :: FormTools, Dumb :: Database, etc.) excepto que, como dije, hay muchos programas que ya 'usar tonto';

me gustaría exportar funciones exportables de Dumb Dumb :: base de datos a través sin tener que tener variaciones de este una y otra vez:

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

No es que estoy por encima de eso. Es solo que esto parece ser la forma tonta y poco elegante de manejar el problema. Utilicé la excusa "No sé, no, mejor" una vez, y una vez es realmente más de lo que obtienes. ¿Ayuda?

+2

no tengo tiempo para escribir una respuesta adecuada, pero se puede utilizar una costumbre '' Por importación función en Dumb' que encamina las llamadas a 'Por importación a la varios módulos secundarios. – daotoad

+2

¿Solo 2k LOC? Guau, ¡un lindo y pequeño módulo! ;) –

+3

... y luego estaba el monstruo de 14K con 7K de registros de commit que heredé en mi último trabajo ... – Penfold

Respuesta

3

No estoy seguro de cómo lo está usando actualmente (¿actualmente exporta métodos?), Pero puede configurar los nuevos módulos secundarios para permitirle importar sus funciones (usando Exporter), y luego simplemente tener el módulo original explícitamente importar las piezas ahora rotas. Algo así como:

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; 
+0

Solo pude hacer que funcione si utilicé "use Exporter qw (import);" pero eso significa que pude hacerlo funcionar. ¡Gracias! –

+0

También puede heredar de Exporter, que es lo que quise que hiciera allí. Lo he corregido por eso, lo siento. – macabail

7

Es difícil darle consejos específicos debido a diferentes bases de código requieren diferentes estrategias. Refactorizo ​​un módulo con subrutinas de 500 líneas de forma diferente a una con pequeñas subrutinas y una gran cantidad de código repetido. Si también necesito cambiar la interfaz, existen diferentes estrategias para eso.

  1. Pon todo en control de fuente. Debe mantener alrededor de las versiones original e intermedia.
  2. Si aún no tiene un banco de pruebas, escriba uno. Obtenga la cobertura de prueba tan alta como pueda. Este conjunto de pruebas es la base para preservar el mismo comportamiento en las versiones futuras, errores y todo. Probablemente te encuentres con un programa que depende de un error en el módulo original.
  3. Comience a piratear. En cada paso, verifique que el resto todavía pase las pruebas originales y que la interfaz publicada todavía tenga el mismo comportamiento.

Creo que su pregunta real, sin embargo, es "¿Cómo puedo exportar al módulo original que cargó tonto?". Puede proporcionar su propia rutina import que utiliza el método import_to_level del Exportador. Puedes importar a niveles más altos que el inmediato que te cargó. El Dumb::Databaseimport puede cargar sus exportaciones en el espacio de nombres que cargó Dumb aunque es Dumb que carga Dumb::Database.

+2

No veo por qué estás recomendando 'import_to_level'. 'Dumb' va a ser un módulo de compatibilidad con versiones anteriores hasta que' use Dumb; 'pueda ser reemplazado por los módulos individuales que el programa particular necesita. ¿Por qué debería escribir una 'importación' personalizada en cada módulo nuevo que tiene que decidir a qué nivel exportar cuando el stock 'import' permitirá a' Dumb' volver a exportar las funciones que importa de los nuevos módulos? – cjm

+0

Si 'Mudo' necesita ser dividido en módulos separados y los programas de nivel superior todavía quieren obtener las exportaciones de esos módulos separados simplemente usando' Mudo', entonces no quiere importar en 'Mudo'. Sin embargo, no lo recomiendo como la solución si el OP quiere hacer algo más. Hay muchas formas de ir aquí. Tu respuesta funciona, pero creo que es poco elegante que tengas que importar a Dumb para que puedas exportar lo mismo al nivel superior. –

+0

Cuando entendí la pregunta del OP, él tiene un módulo gigante que hace un montón de cosas diferentes. Ojalá hubiera usado módulos individuales, por lo que un script podría cargar solo los que realmente usaba. Pero no quiere tener que rastrear cada programa que dice 'use Dumb' y arreglarlo para importar los módulos correctos. Necesita un Dumb.pm con las exportaciones existentes para compatibilidad con versiones anteriores, por lo que puede corregir gradualmente los programas que 'usan Dumb' para usar solo los módulos que realmente necesitan. – cjm

3

Supongo que Dumb.pm actualmente usa Exporter. Suponiendo que no desea cambiar el nombre de las funciones (simplemente divídalas en módulos separados), debe poder mantener las definiciones existentes @EXPORT, importar todo de sus submódulos y simplemente reexportar las funciones.

package Dumb; 
use Dumb::FormTools ':all'; 
use Dumb::Database ':all'; 

use Exporter 'import'; 

our @EXPORT = ...; # Unchanged from original version 
our @EXPORT_OK = ...; # Unchanged from original version 

1; 

La etiqueta :all no está definido por defecto. Debe definirlo manualmente (en cada submódulo).

our %EXPORT_TAGS = (all => [ @EXPORT, @EXPORT_OK ]); 
# or, for a module that doesn't export anything by default: 
our %EXPORT_TAGS = (all => \@EXPORT_OK); 

Por otro lado, si un submódulo no tiene @EXPORT_OK funciones, entonces puede saltarse la etiqueta :all y decir use Dumb::Submodule;.

Cuestiones relacionadas