El código heredado se refiere al código de software que todavía cumple su propósito, pero que se desarrolló utilizando tecnologías ahora obsoletas. Abarca el código heredado de otro equipo o de una versión de software anterior y el código fuente que ya no se admite ni se mantiene activamente. También incluye código escrito con hardware o sistemas operativos obsoletos, compiladores o interfaces de programación de aplicaciones (API) desactualizados, o lenguajes de programación o entornos de desarrollo de software obsoletos. Como resultado, el código heredado ya no cumple con los nuevos Resultados de codificación, los principios de diseño de software actuales o la arquitectura informática más reciente.
En su libro de 2004 Working Effectively with Legacy Code, Michael Feathers lo describió de otra forma: "código sin pruebas"1. Esta definición de código legado significa que los programadores no tienen forma de verificar que el código funciona y funciona como se esperaba. Muchos sistemas heredados también carecen de documentación adecuada, vital para entender su comportamiento, lo que hace que ampliarlos o mejorarlos sea un trabajo pesado para los desarrolladores.
El código heredado contribuye a deuda técnica, que debe "pagarse" con el tiempo mediante el mantenimiento continuo del código. A continuación, se presentan algunos desafíos comunes que las Organizaciones pueden enfrentar al mantener el código heredado:
● Adaptabilidad
● Coste
● Rendimiento
● Escalabilidad
● Seguridad y cumplimiento
Debido a su naturaleza obsoleta, el código heredado puede ser incompatible o difícil de integrar con sistemas más modernos. Esta falta de adaptabilidad puede obstaculizar la innovación y desacelerar el crecimiento empresarial, haciendo que las empresas pierdan potencialmente su ventaja competitiva.
El mantenimiento de los sistemas heredados puede resultar caro. Estos costes operativos y de mantenimiento pueden acumularse, ya que las tarifas de soporte de terceros aumentan para las versiones antiguas de software y hardware. Además, encontrar desarrolladores expertos en prácticas informáticas o lenguajes de programación anticuados puede resultar difícil y tiene un precio.
Las arquitecturas torpes y monolíticas provocan una alta latencia, tiempos de respuesta lentos y tiempos de inactividad frecuentes. Este rendimiento lento puede afectar negativamente a la experiencia del usuario, reduciendo la satisfacción del cliente. También puede obstaculizar la productividad y la eficiencia de los miembros del equipo que trabajan con estos sistemas y los mantienen.
Los sistemas anticuados pueden verse afectados por el aumento de la carga de usuarios. Se esfuerzan por satisfacer el aumento de la demanda y aumentar o reducir según sea necesario. Sus componentes estrechamente acoplados también dificultan la mejora de las características existentes o la adición de nuevas características.
Es posible que el código antiguo no se actualice activamente con parches de seguridad ni siga las últimas normas de seguridad, por lo que se vuelve vulnerable a los ciberataques y las infracciones. Los sistemas heredados también pueden no cumplir con la normativa actual.
La modernización de las aplicaciones heredadas requiere una planificación cuidadosa. He aquí una metodología de cinco pasos para ayudar a agilizar el proceso:
● Comprender la base de código
● Dividir y vencer
● Pruebas de caracterización artesanal
● Refactorizar, migrar o reescribir
● Probar y documentar
El primer paso es comprender el código base, y suele ser la parte más difícil. Comience con la revisión de cualquier documentación disponible, ya sean documentos de requisitos, comentarios de código en línea o historial de control de versiones, como registros de confirmación o registros de cambios.
Cuando la documentación sea insuficiente, intente utilizar herramientas de análisis de código estático que examinen automáticamente el código sin ejecutarlo. Además, las herramientas de visualización de código pueden crear una representación gráfica de la estructura del código fuente, lo que ayuda a trazar dependencias e interacciones entre elementos.
Una vez que los equipos de desarrollo de software dominan lo suficiente el sistema heredado, pueden empezar a abordar el sistema heredado. Estas bases de código en expansión pueden ser abrumadoras, así que divídalas en módulos más pequeños y manejables y trabaje en un módulo a la vez.
Las pruebas suelen escribirse para validar la corrección del código y su comportamiento previsto. Sin embargo, las pruebas de caracterización se crean para comprender qué hace el código y cómo funciona. Esto es útil para comprender el código heredado2 .
Las empresas suelen tener tres opciones a la hora de modernizar el código heredado: refactorizar, migrar o reescribir. También pueden combinar cualquiera de estos enfoques. Decidir qué camino seguir requiere la participación tanto del equipo de ingeniería de software como del equipo de liderazgo empresarial.
La refactorización de código altera la estructura interna del código fuente sin modificar su comportamiento externo ni afectar a su funcionalidad. Es menos probable que estos pequeños cambios introduzcan errores y pueden dar como resultado un código claro y limpio que sea más fácil de mantener.
En el caso del código heredado, los equipos pueden comenzar con modificaciones menores para cada módulo, como el cambio de nombre de las variables, la eliminación de métodos duplicados o no utilizados y la estandarización del formato. A continuación, pueden proceder con una reestructuración más basada en la lógica, como dividir los métodos grandes en otros más pequeños, simplificar los condicionales complejos y mover características entre funciones para reducir las dependencias y mejorar la cohesión.
La migración es otra ruta hacia la modernización del código heredado. Esto implica migrar todo o parte del código a plataformas o pilas tecnológicas más nuevas, como la transición de una arquitectura monolítica a microservicios o el cambio de local a la nube. Es importante comprobar la compatibilidad con la plataforma o la pila tecnológica y confirmar si los proveedores ofrecen algún tipo de soporte durante la migración.
Reescribir el código heredado suele ser el último recurso, ya que implica crear código completamente nuevo para reemplazar el código antiguo. Este es un proyecto nuevo en sí mismo, una tarea enorme que podría requerir un equipo de desarrollo independiente para manejarla.
Tanto la migración como la reescritura pueden ser una tarea desalentadora para enormes bases de código heredado, por lo que los equipos pueden considerar la estrategia de "higo estrangulador"3. Una higuera estranguladora crece en lo alto de la superficie de un árbol, sus raíces descienden hasta el suelo, envolviendo lentamente a su árbol anfitrión en una red constrictora que finalmente hace que se marchite.
En términos de sistemas heredados, los equipos pueden migrar o reescribir de forma incremental pequeños fragmentos de código hasta que todo el código base se haya cambiado a un marco moderno o se haya desarrollado en un lenguaje de programación actual. Sin embargo, los equipos deben crear una arquitectura de transición para que el código existente y el nuevo código coexistan. Esta arquitectura de transición se retirará una vez que se complete la migración o la reescritura3.
Es crucial probar exhaustivamente el código refactorizado, migrado o reescrito para asegurarse de que no aparezcan errores. Los desarrolladores pueden escribir sus propias pruebas de integración y unidades, pero también es esencial involucrar a los equipos de control de calidad que pueden ejecutar pruebas funcionales, de regresión e integrales para comprobar que las características y los comportamientos están intactos.
La documentación es otra parte crítica del flujo de trabajo de modernización. Documente los cambios en el código fuente, ya sea anotando el código mediante comentarios en línea, creando registros de cambios detallados o escribiendo documentos completos de arquitectura y diseño y otra documentación técnica.
Varias herramientas pueden ayudar a acelerar y automatizar el proceso de modernización del código heredado. Estos son algunos de los más comunes:
● Analizadores de código estático
● Aplicaciones de visualización de código
● Marcos de automatización de pruebas
● Plataformas y kits de herramientas de migración
● Generadores de documentos
Los analizadores estáticos pueden ayudar a depurar el código heredado para detectar defectos de programación, problemas de calidad e incluso vulnerabilidades de seguridad. Muchas herramientas de análisis de código estático son compatibles con lenguajes de programación heredados como C, COBOL, PL/I y RPG. Algunos ejemplos de analizadores de código estático son CodeSonar, Klocwork, el PMD de código abierto y SonarQube.
Los visualizadores de código representan gráficamente el código fuente para ofrecer una mejor imagen de su funcionamiento, especialmente en el caso de bases de código grandes o complejas. Estas representaciones gráficas se presentan en distintos formatos, como mapas de código, diagramas de flujo y diagramas del lenguaje unificado de modelado (UML). Algunos ejemplos de aplicaciones de visualización de código son CodeScene, CodeSee y Understand, entre otras.
Estos marcos crean y ejecutan pruebas automatizadas y producen informes sobre esas pruebas. Los marcos de automatización de pruebas más populares incluyen Cypress y Selenium para aplicaciones web y Appium para aplicaciones móviles.
Estas plataformas y kits de herramientas ayudan a simplificar y automatizar los flujos de trabajo de migración para sistemas heredados. Algunas de las principales plataformas de migración son AWS Application Migration Service, Azure Migrate, los kits de herramientas de migración de nube de Google, IBM Cloud Transformation Advisor y Red Hat Migration Toolkit for Applications.
Estas herramientas generan automáticamente la documentación a partir del código fuente y otros archivos de entrada. Ejemplos de herramientas de generación de documentos son Doxygen, Sphinx y Swimm, entre otras.
La inteligencia artificial (IA) puede ayudar en la modernización del código heredado. Las aplicaciones de IA generativa están respaldadas por modelos de lenguaje de gran tamaño (LLM) que pueden analizar bases de código heredadas complejas o enormes.
La IA generativa se puede emplear para ayudar con estas tareas de modernización de código heredada:
● Explicación del código
● Refactorización de código
● Transformación de código
● Generación de pruebas y documentación
La IA generativa puede comprender el contexto y la semántica que sustentan las bases de código heredado. Esto los hace capaces de esbozar la lógica y la función detrás de ellos, explicando el código de una manera que los programadores puedan entender.
Las herramientas con IA pueden ofrecer recomendaciones de refactorización en tiempo real. Por ejemplo, IBM watsonx Code Assistant aprovecha los modelos de IBM Granitepara identificar errores y optimizaciones. A continuación, sugiere correcciones específicas que se alinean con las convenciones de codificación establecidas por un equipo, lo que ayuda a simplificar y acelerar la refactorización del código.
Los sistemas de IA pueden sugerir formas de implementar el código fuente de un lenguaje de programación heredado a uno más moderno. Por ejemplo, IBM watsonx Code Assistant for Z combina automatización e IA generativa para ayudar a los desarrolladores a modernizar las aplicaciones de mainframe. Estas capacidades de IA generativa incluyen la explicación de código para COBOL, JCL y PL/I y la conversión de código COBOL a Java.
Al igual que los marcos de automatización de pruebas, los asistentes de codificación de IA también pueden generar pruebas automáticamente. Además, pueden crear comentarios en línea para documentar lo que hacen ciertos fragmentos de código o fragmentos.
Al igual que con cualquier aplicación con IA, los programadores deben tener cuidado al utilizar la IA para modernizar el código heredado. Deben revisar las salidas para comprobar su precisión y probar cualquier cambio o corrección sugeridos.
Instana simplifica su proceso de migración a la nube al ofrecerle una monitorización exhaustiva y conocimientos que se pueden ejecutar.
Aproveche la IA generativa para una modernización acelerada y simplificada de las aplicaciones de mainframe.
Optimice las aplicaciones heredadas con servicios y estrategias de modernización impulsados por la IA y la nube híbrida.
1 #195 - Working Effectively with Legacy Code and AI Coding Assistant - Michael Feathers. Tech Lead Journal. 14 de octubre de 2024.
2 Characterization Testing. Michael Feathers. 8 de agosto de 2016.
3 Strangler Fig. Martin Fowler. 22 de agosto de 2024.