Scripts Perl antiguos que nadie quiere tocar
Descubre qué scripts Perl antiguos siguen activos, reconstruye sus dependencias de CPAN y revela las reglas de negocio ocultas en regex.

Un directorio Perl con quince años rara vez es un solo sistema. Suele ser un montón de tareas cron, utilidades copiadas, arreglos de emergencia, conexiones con software de terceros y uno o dos programas que aún mueven dinero o datos de clientes cada noche. La primera tarea no es reescribirlo. Primero hay que demostrar qué archivos participan en el comportamiento de producción.
He visto equipos empezar por el script más grande, limpiar su sintaxis y descubrir después que producción llamaba a una copia más pequeña mediante un planificador situado en otra máquina. Así es como un proyecto de modernización ordenado rompe un proceso feo, pero funcional. Trata el sistema activo como una fuente de pruebas. Construye un inventario desde la ejecución hacia afuera y después decide qué merece eliminarse, aislarse, repararse o sustituirse.
Empieza por la ejecución, no por el árbol de código
Un árbol de código no puede decirte qué sigue ejecutándose. Necesitas pruebas de los planificadores, registros de procesos, definiciones de servicios, historial del shell, lanzadores de aplicaciones, marcas de tiempo de archivos y sistemas que consumen la salida. Un archivo puede parecer abandonado mientras un proceso financiero trimestral todavía lo llama. Otro puede recibir cambios diarios de un despliegue sin llegar a ejecutarse nunca.
Busca en todos los planificadores capaces de iniciar trabajo, no solo en el crontab del usuario actual. Revisa los directorios cron del sistema, temporizadores de servicios, planificadores de lotes, tareas de base de datos, sistemas de integración continua, paneles de control y el planificador corporativo que operaciones olvidó mencionar. En máquinas similares a Unix, esta primera pasada aporta pistas útiles sin atribuir a la máquina más certeza de la que puede ofrecer:
ps -eo pid,lstart,args | grep '[p]erl'
find /etc/cron.d /etc/cron.daily /etc/cron.hourly -type f -exec grep -nH 'perl\|\.pl' {} \;
grep -R -n 'perl\|\.pl' /etc/systemd/system /usr/lib/systemd/system
find /opt /srv /usr/local -type f \( -name '*.pl' -o -name '*.pm' \) -print
La salida típica de un proceso incluye un PID, la hora de inicio y la línea de comandos completa. Los argumentos importan porque a menudo seleccionan el modo de negocio real:
1842 Mon Aug 10 01:00:02 2026 /usr/bin/perl /opt/billing/bin/post.pl close
Repite el muestreo de procesos a lo largo del calendario del negocio. Una sola captura pierde tareas que duran segundos. Guarda para cada ejecución observada la ruta original, la ruta del intérprete, el directorio de trabajo, el usuario, los argumentos, el origen del entorno, la condición de inicio, la frecuencia, las entradas, las salidas y el consumidor posterior. Si no puedes nombrar al consumidor, el inventario no está terminado.
Revisa los registros de despliegue como una fuente distinta. Un manifiesto de paquete puede revelar un script instalado fuera de la ruta del repositorio que buscaste, y un antiguo script de entrega puede renombrar o generar Perl durante la instalación. Compara hashes entre máquinas en lugar de fiarte de nombres de archivo iguales. Marca los archivos generados como tales y encuentra la plantilla o el comando que los crea. De lo contrario, un despliegue posterior puede restaurar silenciosamente código que creías retirado. Pregunta también a operaciones por ejecuciones manuales, sobre todo reparaciones de cierre de mes y repeticiones tras fallos parciales. Esos casos muchas veces no dejan una entrada permanente en ningún planificador.
Los registros de las máquinas pueden reforzar las pruebas. La contabilidad de procesos, registros de auditoría, registros del planificador y telemetría de los equipos pueden mostrar ejecuciones históricas. Si esas fuentes nunca estuvieron activadas, indícalo en el inventario. No conviertas la ausencia de registros en la afirmación de que un script está muerto.
Un grafo de llamadas necesita aristas fuera de Perl
El grafo de llamadas útil incluye shell, JCL, entradas del planificador, configuración del servidor web, tareas de base de datos, llegadas de archivos y personas que siguen manuales de operación. El análisis estático de Perl solo cubre una parte. Un require dinámico, nombres de módulos construidos, eval, callbacks y manejadores seleccionados por configuración pueden ocultar aristas incluso dentro del lenguaje.
Empieza con referencias literales y shebangs y sigue hacia afuera desde cada punto de entrada confirmado:
grep -R -n 'use \|require \|do ' /opt/legacy-perl
grep -R -n '/opt/legacy-perl\|perl ' /opt /srv /usr/local/etc
find /opt/legacy-perl -type f -perm -u+x -exec head -n 1 {} \;
Crea un registro con una fila por archivo ejecutable. Asigna a cada fila un estado de prueba: observado, configurado, referenciado o sin referencias. Mantén los estados separados. Una entrada de planificador demuestra configuración, no una ejecución correcta. Un nombre de archivo en un manual demuestra intención humana, no uso actual. Un proceso activo es una prueba fuerte, pero podría ser una tarea bloqueada en lugar de una tarea sana.
Registra después las aristas de entrada y salida. Las de entrada explican cómo comienza la ejecución. Las de salida incluyen módulos, ejecutables, bases de datos, colas, relés de correo, máquinas remotas y archivos. Registra también los formatos de datos. Un archivo separado por tabulaciones con un orden de columnas sin documentar es una interfaz, aunque nadie lo haya llamado así.
La eliminación requiere dos tipos de prueba: ninguna arista de entrada observada o configurada durante un periodo operativo representativo y ninguna salida única que espere otro proceso. Pon el candidato en cuarentena antes de borrarlo. Retira su permiso de ejecución o mueve su entrada de planificador a un archivo desactivado y versionado, y después observa si falla alguna expectativa. Conserva una vía rápida de restauración. El código antiguo no merece inmunidad sentimental, pero la incertidumbre no es una prueba.
Reproduce el intérprete antes de arreglar el código
El comportamiento de Perl depende de algo más que el archivo .pl. Captura el intérprete exacto y sus opciones de compilación antes de probar nada. /usr/bin/perl puede ser distinto de un Perl instalado en /opt, y un wrapper puede alterar PERL5LIB, la configuración regional, la zona horaria o el directorio actual. Esas diferencias pueden cambiar la resolución de módulos, el análisis de fechas, la ordenación y el tratamiento de texto.
Ejecuta lo siguiente como el usuario de producción, desde el directorio de trabajo de producción, y elimina los secretos de la salida guardada:
command -v perl
perl -v
perl -V
perl -e 'print join("\n", @INC), "\n"'
env | grep '^PERL\|^LANG\|^LC_\|^TZ'
perl -V informa de cómo se construyó el intérprete y muestra valores de configuración que explican fallos de portabilidad. El volcado de @INC indica dónde buscará realmente Perl los módulos y en qué orden. Guarda ambos con el inventario. Es fácil pasar por alto una dependencia en un directorio privado de la aplicación si solo inspeccionas la lista de paquetes del sistema operativo.
Las comprobaciones de compilación son útiles, pero hay que interpretar bien su alcance:
perl -c /opt/legacy-perl/bin/post.pl
Un resultado como syntax OK demuestra que la compilación terminó en ese entorno. No demuestra que exista un módulo cargado dinámicamente en una rama poco frecuente, que funcione un acceso a la base de datos ni que el script produzca una salida correcta. Compila cada punto de entrada confirmado con el mismo usuario, entorno, argumentos y directorio de trabajo usados en producción. No empieces añadiendo use strict o cambiando las advertencias en todo el árbol. Son buenas prácticas para código mantenido, pero alteran la superficie de diagnóstico antes de que hayas capturado el comportamiento de referencia.
Meter el entorno antiguo en un contenedor puede ayudar a reproducirlo, pero un contenedor no es una máquina de verdad arqueológica. Las bibliotecas nativas, comandos del sistema, certificados, DNS, permisos del sistema de archivos, datos regionales y comportamiento del planificador siguen fuera de la lista de dependencias Perl. Registra esas aristas en lugar de suponer que la imagen las capturó.
Observa con seguridad antes de instrumentar
La observación en tiempo de ejecución debe empezar fuera del proceso, porque cambiar un script antiguo puede alterar los tiempos, el entorno y la gestión de errores. Empieza por las marcas del planificador, la duración del proceso, los archivos abiertos, procesos hijos, destinos de red, estado de salida y cambios en el sistema de archivos. Recoge esos datos en una copia del entorno siempre que puedas. En producción, utiliza mecanismos de solo lectura ya permitidos por operaciones y fija una ventana breve de observación.
El rastreo de llamadas del sistema sirve cuando el código oculta rutas tras variables o configuración. Una traza puede mostrar qué archivo de módulo se abrió, qué ejecutable lanzó el script y qué archivo de configuración intentó usar antes de recurrir a un valor alternativo. También registra muchos datos sensibles y puede ralentizar un proceso ocupado. Filtra operaciones de archivos y procesos, guarda la traza en almacenamiento protegido y pide a un operador que apruebe el comando. No te conectes sin cuidado a una tarea de pagos o liquidación solo porque el rastreo parezca de lectura. Observar tiene un coste operativo.
Compara el proceso antes y durante la sonda. Registra inicio y fin, consumo de CPU y memoria, estado de salida, recuento de filas o archivos y la señal de fallo habitual. Si la ejecución instrumentada tarda mucho más o cambia el orden, descártala como referencia de comportamiento e investiga la causa. Una sonda que altera el sistema puede descubrir dependencias, pero no debe definir la paridad.
El registro dentro de la aplicación viene después. Actívalo con una variable de entorno que esté apagada de forma predeterminada y emite eventos en límites de negocio, no en cada llamada de subrutina. Un evento útil identifica el modo seleccionado, el identificador de entrada, el resultado de la regla, la ruta de la dependencia, la acción externa y el estado final. No registres filas sin procesar solo porque el código antiguo carezca de clasificación de datos. Oculta los valores antes de serializarlos para que nunca lleguen datos sensibles al destino del registro.
Un wrapper suele ser más seguro que modificar el script. Puede capturar el directorio de trabajo, el entorno saneado, los argumentos, las horas de inicio y fin, el estado de salida y los hashes de resultados concretos. Mantén el orden de argumentos y usa exec cuando el wrapper deba conservar el comportamiento de procesos y señales. Prueba la propagación de señales, porque los planificadores pueden usar señales de terminación para imponer una ventana de ejecución. Un wrapper que se traga la señal cambia el contrato de producción.
No dejes rastreo temporal sin responsable ni fecha de retirada. Los puntos de diagnóstico tienden a quedarse, sobre todo cuando producen el único registro de fallo útil. Si uno merece permanecer, trátalo como observabilidad mantenida: documenta su esquema, rotación, control de acceso, ocultación de datos y comportamiento ante fallos. Decide qué ocurre cuando el destino de los registros se llena o desaparece. Un lote antiguo no debe dejar de contabilizar facturas porque se llene un disco nuevo de diagnóstico.
El resultado de la observación debe actualizar filas concretas del registro. Sustituye una ruta de módulo supuesta por la observada, añade un nuevo proceso hijo o cambia un punto de entrada de configurado a observado. Guarda la traza original por separado, bajo controles de acceso más estrictos, y registra cómo se recogió. Esa separación mantiene útil el inventario sin convertirlo en almacén de datos de clientes o secretos.
Reconstruir CPAN es un trabajo de pruebas
Un módulo mencionado en use no es automáticamente una dependencia de CPAN. Puede venir con esa versión de Perl, proceder de un paquete del sistema operativo, estar dentro del repositorio o ser una copia modificada localmente que comparte el nombre de un módulo público. A la inversa, un script puede cargar un módulo de forma dinámica sin una instrucción use visible. Construye el conjunto de dependencias desde el entorno de ejecución hacia afuera.
Para cada punto de entrada confirmado, captura las rutas de los módulos cargados en un entorno de pruebas seguro:
perl -MData::Dumper -e 'END { print Dumper(\%INC) } do shift' /opt/legacy-perl/bin/post.pl
Esta sonda sencilla no es segura para un script que realiza trabajo en cuanto se carga. Úsala solo en una copia del entorno con las escrituras externas bloqueadas o añade temporalmente un punto de diagnóstico a una rama de prueba. %INC relaciona los nombres de módulos cargados con los archivos que Perl seleccionó y revela copias privadas y sorpresas por el orden de las rutas. Prueba más que el camino correcto, porque las cargas condicionales solo aparecen cuando se ejecuta su rama.
Compara cuatro fuentes: importaciones encontradas en el código, %INC de ejecuciones representativas, archivos en directorios de bibliotecas locales y distribuciones instaladas que declara la máquina original. perldoc perllocal puede contener un registro de módulos instalados mediante herramientas de CPAN, aunque los paquetes del sistema y las copias manuales pueden dejarlo incompleto. La base de paquetes del sistema operativo aporta otra pieza. Ninguna fuente merece ser la única autoridad.
Escribe las dependencias directas reconstruidas y sus restricciones de versión en cpanfile. Fija lo que la aplicación demuestra necesitar, no todos los módulos transitivos presentes en un servidor antiguo. Después utiliza Carton u otro instalador controlado para resolver e instalar en un directorio aislado. Conserva la salida del resolutor y los registros de compilaciones fallidas como pruebas del proyecto.
requires 'DBI', '1.643';
requires 'DateTime', '1.54';
requires 'Text::CSV_XS', '1.49';
Esas versiones son ilustrativas, no recomendaciones. Tus restricciones deben proceder de la máquina que funciona, de los requisitos del código y de las pruebas de comportamiento. Si no se declaró ninguna versión, registra primero la versión instalada que produjo el comportamiento de referencia. Relájala solo después de que las pruebas muestren que otra versión conserva el comportamiento.
Cuando una versión antigua ya no se instala, identifica el fallo exacto. Un compilador ausente, una biblioteca C no disponible, una distribución retirada, una prueba fallida y código incompatible con un Perl nuevo exigen soluciones distintas. No resuelvas las cinco cosas copiando el antiguo directorio site_perl. Esa copia puede conservar un módulo binario compilado para una ABI equivocada y dejar un fallo que solo aparece más tarde bajo carga. Archiva distribuciones y parches originales cuando la licencia lo permita, pero consigue que la nueva compilación se reproduzca a partir de entradas declaradas.
Las expresiones regulares son reglas ejecutables
La regex peligrosa rara vez es la más larga. Es aquella cuyo resultado decide un precio, una clase de cuenta, un destino de encaminamiento, una razón de rechazo o una marca de cumplimiento. Trata esas expresiones como reglas de negocio aunque estén dentro de una sustitución o de un grep de una línea. Las regex de formato y las de decisión necesitan revisiones diferentes.
Encuentra candidatas con la búsqueda de código y clasifícalas por sus consecuencias. La sintaxis de Perl hace poco realista una extracción estática perfecta, así que inspecciona las ramas y salidas cercanas en lugar de contar metacaracteres. Presta especial atención a sustituciones, variables de captura como $1, alternativas con vocabulario de negocio y patrones construidos a partir de la configuración.
El manual perlre explica que Perl elige primero la coincidencia situada más a la izquierda y que los cuantificadores son voraces de forma predeterminada. Parece elemental, pero se convierte en comportamiento de negocio cuando las alternativas se solapan o las capturas alimentan cálculos posteriores. Una limpieza que cambie el orden de las alternativas o añada un ancla puede modificar qué registros de clientes cumplen la regla. Los cambios de Unicode y configuración regional también pueden alterar las clases de caracteres y las conversiones entre mayúsculas y minúsculas.
Convierte cada expresión con consecuencias en una tabla de ejemplos con nombre antes de refactorizarla:
my @cases = (
['ACCT-001-EU', 'eu', 1],
['ACCT-001-US', 'domestic', 1],
['acct-001-eu', undef, 0],
['ACCT-001-EU ', undef, 0],
);
for my $case (@cases) {
my ($input, $class, $accepted) = @$case;
my ($got) = $input =~ /\AACCT-\d{3}-(EU|US)\z/;
my $ok = defined $got ? 1 : 0;
die "acceptance changed for <$input>" if $ok != $accepted;
}
Los valores de ejemplo son inventados para mostrar la forma de una prueba de caracterización. Los casos reales deben proceder de entradas de producción anonimizadas, registros rechazados, ejemplos de operadores y condiciones límite. Conserva los espacios iniciales, la codificación, los finales de línea, los campos vacíos y las entradas mal formadas. Normalizar los datos de prueba demasiado pronto borra el comportamiento que necesitas descubrir.
No traduzcas una regex densa directamente a otra expresión igual de densa en el lenguaje de destino. Primero da nombre a la regla con términos del dominio, conserva el patrón original como oráculo para los casos y escribe pruebas para valores aceptados, rechazados y campos extraídos. Algunas expresiones deberían convertirse en código de análisis normal o en una tabla porque la regla necesita que la revisen personas que no hablan regex.
Registra el comportamiento en los límites del sistema
Las pruebas unitarias añadidas a componentes internos antiguos suelen consagrar accidentes de implementación mientras pierden el contrato del que dependen otros sistemas. Captura primero el comportamiento en los límites: archivos de entrada, argumentos de comandos, lecturas de base de datos, filas emitidas, códigos de salida, salida estándar, error estándar, mensajes y cambios de estado. Así habrá espacio para cambiar la arquitectura interna después.
Elige un conjunto representativo a partir del tráfico de producción grabado o de entradas copiadas de forma segura. Elimina o sustituye por tokens los valores sensibles, pero conserva longitudes, clases de caracteres, delimitadores y relaciones que afectan al análisis. Para cada ejecución, guarda la huella del intérprete, el bloqueo de dependencias, el entorno, el hash de entrada, la salida, el estado de salida y las escrituras visibles externamente. Fija el tiempo y las fuentes aleatorias cuando el programa lo permita. Si no, compara campos estables y describe explícitamente cada campo ignorado.
Un pequeño arnés de shell puede revelar más que una semana de lectura especulativa:
case_dir=/tmp/perl-parity-case-01
mkdir -p "$case_dir"
cp fixtures/invoice.dat "$case_dir/input.dat"
cd "$case_dir" || exit 1
TZ=UTC LC_ALL=C /opt/oldperl/bin/perl /opt/app/run.pl input.dat >stdout.txt 2>stderr.txt
printf '%s\n' "$?" >exit-status.txt
find . -type f -print | sort >files.txt
Ejecuta ese arnés en un entorno aislado porque el script podría enviar correo, modificar una base de datos o invocar otro ejecutable. Redirigir la salida estándar no contiene los efectos secundarios. Sustituye los destinos externos por grabadores cuando sea posible o restaura una instantánea de la base de datos entre casos.
Compara los datos estructurados como estructuras. Ordena solo cuando el contrato diga que el orden no importa. Normaliza marcas de tiempo solo si los consumidores las ignoran. Una limpieza general de espacios puede ocultar daños en registros de ancho fijo; una ordenación general de JSON puede ocultar un cambio de orden en una matriz. Cada normalizador afirma algo sobre el contrato y debe revisarse como código.
La responsabilidad mantiene vivo el inventario
Un inventario sin responsable se convierte en otro artefacto abandonado. Asigna un responsable técnico y otro de negocio a cada punto de entrada activo. El técnico puede explicar cómo se ejecuta y cómo se restaura. El de negocio puede decir qué resultado admite y aprobar cambios en ese resultado. Si nadie acepta la responsabilidad de negocio, eleva ese hecho antes de retirar nada.
Guarda el registro en el control de versiones junto al trabajo de modernización. Una fila útil incluye el estado de la prueba, la última ejecución confirmada, la programación, la identidad del entorno, entradas, salidas, consumidores, manifiesto de dependencias, sensibilidad de los datos, señal de fallo, procedimiento de reinicio y decisión. No incluyas enlaces a paneles volátiles. Guarda identificadores duraderos que un operador pueda buscar.
Establece cuatro decisiones y no finjas que son etapas de una sola cadena:
- Retira código con pruebas convincentes de falta de uso y un periodo de cuarentena reversible.
- Aísla código activo cuyo comportamiento importa, pero cuyo riesgo de cambio supera ahora su coste de mantenimiento.
- Repara código que pueda seguir en Perl con un entorno reproducible, pruebas y un responsable.
- Reescribe código cuya función de negocio siga siendo necesaria y cuyos riesgos de entorno, arquitectura o personal justifiquen sustituirlo.
Un script pequeño puede merecer una reescritura porque controla una liquidación. Un programa grande de informes puede merecer aislamiento porque es estable, está separado y resulta fácil de operar. El número de líneas es una mala aproximación al riesgo de negocio. Usa las consecuencias, la frecuencia de cambio, la capacidad de recuperación, la salud de las dependencias y la calidad del comportamiento observado.
Haz visibles las incógnitas
Añade una columna explícita para incógnitas en lugar de forzar cada fila a un estado seguro. Ejemplos habituales son un alias de base de datos sin verificar, un directorio de salida sin consumidor conocido, una contraseña aportada por un wrapper desconocido o un módulo encontrado en una sola máquina. Asigna a cada incógnita un responsable y una próxima observación. Si no hay una observación prevista, se ha convertido silenciosamente en un riesgo aceptado.
El registro también debe distinguir una instancia de script de un archivo fuente. El mismo archivo puede ejecutarse con dos cuentas, configuraciones, argumentos y permisos distintos. Son dos comportamientos de producción y podrían requerir decisiones diferentes. Calcula el hash del archivo desplegado para detectar copias distintas bajo rutas aparentemente iguales. Registra los destinos de enlaces simbólicos porque un cambio de versión puede hacer que la ruta de ayer apunte al código de hoy.
Los fallos revelan dependencias que las ejecuciones correctas ocultan. Revisa el correo del planificador, directorios de mensajes fallidos, archivos de salida parciales, scripts de repetición y tickets de operaciones. Un comando de recuperación copiado en un manual puede ser la única arista de entrada de un script de reparación. Si el equipo lo borra porque la producción normal nunca lo llama, el siguiente lote fallido se convierte en el mecanismo de descubrimiento. Marca como activos los puntos de entrada exclusivos para recuperación y pruébalos con un fallo reversible.
La retirada también necesita un contrato de salida. En un informe, identifica quién lo recibe y qué hace cuando falta. En una transferencia, identifica el acuse de recibo o el registro de conciliación. En una tarea de limpieza, identifica el síntoma de almacenamiento, latencia o corrección que reaparece cuando se detiene. Un script sin llamador visible aún puede impedir un resultado negativo, como filas duplicadas o datos temporales sin caducar. Busca la condición que suprime.
Usa el registro durante los incidentes. Cuando un operador encuentre una nueva ejecución, actualice un intérprete o descubra un consumidor, cambia el registro en el mismo commit que la reparación operativa. Tras varios ciclos de incidentes, el inventario gana precisión porque incorpora pruebas obtenidas bajo presión real. Una hoja de cálculo enviada una vez a dirección envejece porque quienes aprenden datos nuevos no pueden actualizarla donde trabajan.
Elige un límite de capacidad, no un archivo
Una reescritura archivo por archivo conserva los accidentes de la organización antigua. Elige un límite alrededor de una capacidad observable: ingerir un flujo, clasificar registros, calcular un cargo, producir un informe o contabilizar un lote. Define el límite con entradas, salidas, comportamiento ante errores y cambios de estado, y ejecuta después los mismos casos contra las implementaciones antigua y nueva.
Los despliegues de tipo strangler son populares porque reducen el tamaño del cambio, pero son incorrectos cuando el límite propuesto comparte transacciones o estado mutable que no puede separarse con seguridad. Ejecutar dos escritores contra un esquema mal entendido crea más ambigüedad que reemplazar un lote coherente. En ese caso, construye un lector en sombra, compara salidas y cambia todo el límite de escritura cuando la paridad sea sólida. El límite debe seguir la propiedad de los efectos, no los nombres de las funciones Perl.
No transliteres los modismos de Perl a otro lenguaje. Las variables globales implícitas, valores de retorno dependientes del contexto, autovivificación, valores de verdad y efectos secundarios de regex pueden haber dado forma al programa antiguo, pero la arquitectura nueva debe hacer explícitos el estado y los errores. Conserva el comportamiento externo que necesitan los consumidores. Sustituye el comportamiento interno que existe solo porque Perl lo hacía cómodo.
CodeHero lee todo el árbol con varios lenguajes, reescribe Perl en Go, Rust o TypeScript y comprueba el comportamiento con un arnés de paridad contra tráfico de producción grabado. Ese método encaja solo cuando ya existen pruebas de ejecución y casos en los límites. Una reescritura automatizada no puede recuperar una entrada trimestral que nadie capturó ni una decisión de un operador que vivía fuera del código.
Los primeros diez días deben reducir incertidumbre
Los primeros días de trabajo deben producir pruebas, no un módulo reescrito. El primer día, detén la limpieza casual e identifica máquinas, repositorios, planificadores y personas que reciben salidas. Para el tercer día deberías tener puntos de entrada confirmados, huellas del entorno y una lista de consumidores desconocidos. Para el sexto, las ejecuciones representativas deberían mostrar dependencias cargadas y efectos en los límites. Para el décimo, el equipo debería poder defender cada decisión con registros en lugar de confianza.
Mantén segura la producción mientras reúnes las pruebas. Lee la configuración antes de cambiarla. Captura comandos y salidas en un registro controlado. Elimina secretos. Ejecuta scripts copiados solo después de bloquear el correo, escrituras de base de datos, llamadas remotas y rutas destructivas del sistema de archivos. Pide a un operador que revise cualquier sonda que toque un planificador activo o una cuenta de producción.
El hallazgo incómodo puede ser que nadie sepa reconstruir el intérprete, varias versiones de CPAN hayan desaparecido de las rutas habituales de instalación y la única especificación sea una regex junto con los archivos del año pasado. Eso sigue siendo progreso. Ahora sabes dónde vive el riesgo. Conserva el entorno funcional, recoge entradas representativas, nombra al responsable de negocio y convierte el comportamiento en pruebas ejecutables.
No premies al primer ingeniero que haga que el código antiguo parezca moderno. Premia a quien demuestre qué sigue pidiéndole el negocio. Cuando exista esa prueba, borrar y reescribir serán decisiones de ingeniería en lugar de folclore.
Preguntas frecuentes
¿Cómo puedo saber si un script Perl antiguo sigue ejecutándose?
Recoge pruebas de procesos, todos los planificadores, definiciones de servicios, registros de auditoría y salidas posteriores. La ausencia de cambios recientes no demuestra nada, y una entrada de planificador demuestra configuración, no una ejecución correcta.
¿Cuánto tiempo debo observar antes de declarar que un script Perl no se usa?
Observa durante el ciclo de negocio relevante más largo, incluidos cierres de trimestre, cierres de año y ejecuciones excepcionales aplicables. Si no puedes observar todo ese ciclo, pon el script en cuarentena de forma reversible y vigila salidas ausentes o expectativas incumplidas.
¿Debo añadir strict y warnings antes de auditar Perl antiguo?
No en todo el árbol. Captura primero el intérprete, el entorno y el comportamiento de referencia, y después introduce diagnósticos en una rama controlada donde puedas separar advertencias nuevas de cambios de comportamiento.
¿Cómo encuentro los módulos CPAN que usa una aplicación Perl?
Combina importaciones estáticas, %INC capturado en ejecuciones representativas, directorios privados de bibliotecas, registros de paquetes de la máquina e historial de instalación. Ninguna fuente ve por sí sola las cargas dinámicas, copias locales y paquetes del sistema.
¿Qué hago cuando un módulo CPAN antiguo ya no se instala?
Identifica si el fallo procede del compilador, una biblioteca nativa, una versión ausente, una prueba o una incompatibilidad con la versión de Perl. Conserva el artefacto funcional y después cambia una sola causa diagnosticada cada vez, protegida por pruebas de límites.
¿Puedo copiar site_perl desde el servidor antiguo?
Usa la copia como prueba forense, no como nuevo proceso de compilación. Los módulos binarios pueden apuntar a la ABI del intérprete antiguo, y los árboles copiados ocultan las entradas necesarias para una instalación repetible.
¿Cómo pruebo reglas de negocio ocultas en regex de Perl?
Construye una tabla con nombre de entradas aceptadas, rechazadas y límite a partir de registros reales anonimizados. Comprueba tanto la decisión de coincidencia como los campos capturados, porque el código posterior suele tratarlos como datos de negocio.
¿Basta con poner el entorno Perl antiguo en un contenedor?
Puede conservar parte del entorno, pero no captura automáticamente bibliotecas nativas, comandos, certificados, permisos, datos regionales ni servicios externos. Haz inventario de esos límites y pruébalos de manera explícita.
¿Se debe reescribir el Perl antiguo archivo por archivo?
Normalmente no. Elige un límite de capacidad con entradas, salidas, errores y cambios de estado observables, y compara allí las implementaciones antigua y nueva.
¿Cuándo es más seguro conservar un script Perl?
Aíslalo cuando sea estable, esté separado, pueda reproducirse, tenga un responsable y cueste menos operarlo que sustituirlo. La edad por sí sola no exige una reescritura. Las consecuencias sin límite y el conocimiento irrecuperable del entorno son motivos más fuertes.