Aplicación Legacy – Reingeniería con SonarQube (II)

Application Legacy – Reengineering avec SonarQubeHemos visto en el post anterior cómo iniciar una reingeniería con SonarQube empezando con una redistribución funcional y un nuevo diseño de nuestra aplicación.

Ahora podemos ir un poco más profundo en el código para identificar a los flujos de tratamientos candidatos para la reestructuración.

Reestructuración de los tratamientos

Otra vez voy a utilizar el SQALE Sunburst para navegar entre las diferentes violaciónes de las mejores prácticas de programación para buscar cualquier indicio de ‘código espagueti’.

Figure 1 – Refactoring de ‘goto’

Plugin SQALE - Refactoring de goto

Este widget me permite cuantificar el esfuerzo de refactorización – 158,8 días – para corregir estos defectos de flujos de tratamientos y los saltos de algoritmos por todos caminos y direcciones.
Yo puedo hacer lo mismo para cada uno de los fallos de este tipo, por ejemplo, el uso de ‘continue’. A continuación, un clic en esta ‘Issue’ en el SQALE Sunburst me lleva a la lista de programas con estas violaciónes, en la figura siguiente:

Figura 2 – Lista de violaciónes ‘continue’ SonarQube - Avoid continue

A partir de ahí, puedo hacer un drill-down con cada programa y comprobar el código de cada línea que tiene una de estas violaciónes. En la siguiente figura, podemos ver una línea de código con un ‘continue’ y el ‘break’ que lo acompaña, y la estimación – 30 minutos – de deuda técnica para resolver este código espagueti.

Figura 3 – Línea de código con violación y evaluación de la carga de la resolución

LegacyApp_RemoveContinue
Podemos ver en este ejemplo cómo utilizar SonarQube para ir directamente al grano:

  • Una estimación global de la refactorización de los flujos de tratamientos a través del plugin SQALE.
  • Una estimación más detallada, por lo menos para los componentes más importantes y más complejos que pesarán más en la carga global de reingeniería.

El equipo de proyecto puede hacer un drill-down en cada programa, como lo hicimos en este ejemplo, para evaluar el nivel de la destructuración del código y reescribirlo de acuerdo con la lógica funcional, pero modificando la lógica algorítmica. La solución a los ‘goto’, ‘break’ y ‘continue’ es simple: el uso de ‘if..else’. Sin embargo, cuidado de no demasiado imbricar ‘if..else’ dentro de otros ‘if..else’ en demasiados niveles.

Cada idioma tiene sus propias características en términos de procesamiento de flujo, y las malas prácticas en esta área serán diferentes en C, en Cobol, o en ABAP. Lo importante es tomar en cuenta este punto, y vimos cómo SonarQube nos podría ayudar.

Reestructuración de los datos

Una reingeniería de tratamientos suele ir usualmente con una reingeniería de los datos. Todo un tema en sí mismo, se podría escribir un libro entero sobre esto. Rápidamente, unas pocas ideas de investigación que vienen a la mente:

  • Comprobar si la aplicación utiliza archivos, y si sería posible convertirlos en tablas. Si la información es temporal, como un log de mensajes, tendemos a guardarla en un fichero aunque tampoco sería una mala idea hacerlo en una base de datos porque un ‘Insert’ es más rapido que escribir una línea en un archivo, y en los dos casos, temprano o tarde, tendremos que vaciar el fichero o la tabla.
  • Identificar las características del tipo de datos, el tamaño o la precisión y notar lo que parece extraño o inusual. Validar con los usuarios y aprovechar la oportunidad para preguntarles si tienen alguna petición al respecto.
  • Comprobar si existen estructuras de datos compartidas, y cuales componentes utilizan las mismas tablas. Los accesos múltiples en una tabla son una fuente importante de errores y de costes de mantenimiento. He visto aplicaciones en las que se accedía a una tabla en Insert/Update/Delete por más de 80 clases diferentes. Cada vez que un desarrollador necesitaba un tratamiento en esta tabla, programaba sus propias consultas SQL sin verificar antes que ya existía este mismo tratamiento. Resultado: un cambio de la estructura de la tabla obligaba a verificar y posiblemente modificar estas clases. ¡Puedes imaginar la inversión necesaria para esta tarea y el nivel de riesgo si se olvida uno de estos métodos!
  • Y mientras tanto, comprobar que no haya datos redundantes.
  • Lo mismo para las inconsistencias de datos: una pantalla con una medida en km y otra en metros, o en euros y en K€, o en días y otra en horas, o en horas y en minutos, etc.
  • A ver si tenemos defectos en el código SQL. ¿Por qué esos ‘select *’, ‘select … en select’ o JOIN en múltiples tablas, o anidados, etc. Hemos vimos muchos de ellos en nuestra serie sobre el análisis de código PL/SQL con SonarQube.

Si encontramos tablas temporales construidas dinámicamente durante una sesión, esto usualmente significa procesos muy complejos que no es posible realizar mediante ‘simples’ bucles o con cursores, como un cálculo de agregación estadística. En tal caso, los usuarios tienen que certificarme de la criticidad de estos tratamientos. Porque no podemos tener una misma aplicación con el requerimiento de visualizar en la pantalla todos los datos de cualquier cliente en menos de un segundo y, al mismo tiempo, poder correlacionar dinámicamente todos los datos en todo tipo de estadísticas. Estas son dos aplicaciones diferentes, una de gestión y la otra de Infocenter.

Otros puntos

Comprobar el nivel de comentarios en la aplicación original y tratar de mantener o mejorar este nivel de documentación.

Normas de denominación: si no existen, es hora de decidirlas para los futuros desarrollos con este nuevo lenguaje. Si existen, asegúrate de actualizarlas, pero en base a las normas actualmente en uso, lo que también significa verificar esas opciones con los otros equipos de proyecto, y asegurarse de que todo el mundo utiliza los mismos estándares.

Utilizar una herramienta de análisis de código para comprobar regularmente que no se introducen violaciones de buenas prácticas en el nuevo lenguaje, que no son necesariamente las del lenguaje anterior. Ok, hay numerosos defectos en C que existen en C++, pero lo contrario no es cierto.

Por encima de todo, tener en cuenta las pruebas unitarias. Ya habíamos hecho una estimación del esfuerzo y de los planes de acción en este tema.

Conclusión

No hemos listado todas las posibles tareas de reingeniería que incorporar en el proyecto, se puede imaginar muchas otras. De hecho, esto va a ser muy dependiente del proyecto, la aplicación, la tecnología, etc. No hay un único camino que siempre garantiza el éxito del proyecto, pero hay una buena probabilidad de que los puntos enumerados en este post te ayudan a mejorar las posibilidades de exito de tu reingeniería.

Un último consejo, pensar en el futuro: la portabilidad de aplicaciones en el Cloud, es decir, la disociación de ciertos tipos de tratamiento, las API Restfull, la estrategia de stateless/stateful, etc.
Además, creo que vamos a ver más y más reingenierías de aplicaciones con el fin de subirlas en la nube.

Este articulo pone fin a esta larga serie sobre la refactorización y la reingeniería de una aplicación Legacy. Para los próximos posts, creo que voy a actualizar mi instalación SonarQube y ver lo que ha cambiado con código Cobol y SAP.

Hasta pronto.

Esta entrada está también disponible en Lire cet article en français y Read that post in english.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *